package com.crm.business.crm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.crm.business.admin.service.AdminFileService;
import com.crm.business.admin.service.AdminService;
import com.crm.business.admin.service.IAdminDeptService;
import com.crm.business.admin.service.IAdminMessageService;
import com.crm.business.crm.mapper.CrmReceivablesDataMapper;
import com.crm.business.crm.mapper.CrmReceivablesMapper;
import com.crm.business.crm.service.*;
import com.crm.business.examine.service.ExamineService;
import com.crm.common.admin.entity.PO.AdminDept;
import com.crm.common.crm.constant.*;
import com.crm.common.crm.entity.BO.*;
import com.crm.common.crm.entity.VO.CrmRoiStatisVO;
import com.crm.common.ka.core.feign.admin.entity.AdminConfigBo;
import com.crm.business.utils.ActionRecordUtil;
import com.crm.common.crm.common.CrmModel;
import com.crm.common.crm.common.ElasticUtil;
import com.crm.common.crm.entity.PO.*;
import com.crm.common.crm.entity.VO.CrmFieldSortVO;
import com.crm.common.crm.entity.VO.CrmInfoNumVO;
import com.crm.common.crm.entity.VO.CrmModelFiledVO;
import com.crm.common.ka.core.common.Const;
import com.crm.common.ka.core.common.log.BehaviorEnum;
import com.crm.common.ka.core.entity.BasePage;
import com.crm.common.ka.core.entity.UserInfo;
import com.crm.common.ka.core.exception.CrmException;
import com.crm.common.ka.core.feign.admin.entity.AdminMessage;
import com.crm.common.ka.core.feign.admin.entity.AdminMessageEnum;
import com.crm.common.ka.core.feign.examine.entity.ExamineRecordReturnVO;
import com.crm.common.ka.core.feign.examine.entity.ExamineRecordSaveBO;
import com.crm.business.servlet.BaseServiceImpl;
import com.crm.common.ka.core.redis.Redis;
import com.crm.common.ka.core.servlet.upload.FileEntity;
import com.crm.business.utils.UserCacheUtil;
import com.crm.business.utils.UserUtil;
import com.crm.common.utils.DateUtils;
import com.crm.common.utils.StringUtils;
import com.crm.common.utils.bean.BeanExtendUtils;
import com.crm.common.utils.bean.BeanUtils;
import com.crm.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 回款表 服务实现类
 * </p>
 *
 * @author zhangzhiwei
 * @since 2020-05-28
 */
@Service
@Slf4j
public class CrmReceivablesServiceImpl extends BaseServiceImpl<CrmReceivablesMapper, CrmReceivables> implements ICrmReceivablesService, CrmPageService {

    @Autowired
    private ICrmFieldService crmFieldService;

    @Autowired
    private ICrmReceivablesDataService crmReceivablesDataService;

    @Autowired
    private ICrmContractService crmContractService;

    @Autowired
    private ICrmExamineService crmExamineService;

    @Autowired
    private ICrmExamineLogService examineLogService;

    @Autowired
    private ICrmExamineRecordService examineRecordService;

    @Autowired
    private AdminService adminService;

    @Autowired
    private ICrmNumberSettingService crmNumberSettingService;

    @Autowired
    private ICrmActivityService crmActivityService;

    @Autowired
    private ICrmReceivablesPlanService crmReceivablesPlanService;

    @Autowired
    private ICrmActionRecordService crmActionRecordService;

    @Autowired
    private ICrmCustomerService crmCustomerService;

    @Autowired
    private ActionRecordUtil actionRecordUtil;

    @Autowired
    private AdminFileService adminFileService;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private ExamineService examineService;

    @Autowired
    private ICrmReFundService crmReFundService;

    @Autowired
    private ICrmStudentService crmStudentService;

    @Autowired
    private Redis redis;

    @Autowired
    private IAdminMessageService adminMessageService;

    @Autowired
    private IAdminDeptService adminDeptService;


    /**
     * 大的搜索框的搜索字段
     *
     * @return fields
     */
    @Override
    public String[] appendSearch() {
        return new String[]{"number", "customerName", "studentsCall"};
    }

    @Override
    public CrmEnum getLabel() {
        return CrmEnum.RECEIVABLES;
    }

    //回款更新ROI数据判断
    public static boolean IS_DELETE = true;

    /**
     * 查询所有字段
     *
     * @return data
     */
    @Override
    public List<CrmModelFiledVO> queryDefaultField() {
        List<CrmModelFiledVO> filedList = crmFieldService.queryField(getLabel().getType());
        filedList.add(new CrmModelFiledVO("lastTime", FieldEnum.DATETIME, 1));
        filedList.add(new CrmModelFiledVO("updateTime", FieldEnum.DATETIME, 1));
        filedList.add(new CrmModelFiledVO("createTime", FieldEnum.DATETIME, 1));
        filedList.add(new CrmModelFiledVO("ownerUserId", FieldEnum.USER, 1));
        filedList.add(new CrmModelFiledVO("createUserId", FieldEnum.USER, 1));
        filedList.add(new CrmModelFiledVO("createDeptId", FieldEnum.STRUCTURE, 1));
        filedList.add(new CrmModelFiledVO("ownerDeptId", FieldEnum.STRUCTURE, 1));
        filedList.add(new CrmModelFiledVO("checkStatus", FieldEnum.TEXT, 1));
        filedList.add(new CrmModelFiledVO("planId", FieldEnum.TEXT, 1));
        filedList.add(new CrmModelFiledVO("createDeptName", FieldEnum.TEXT, 1));
        filedList.add(new CrmModelFiledVO("courseSource", FieldEnum.TEXT, 1));
//        filedList.add(new CrmModelFiledVO("ownerOrderPool", FieldEnum.TEXT, 1));
        //filedList.add(new CrmModelFiledVO("salesUserId", FieldEnum.USER,1));
        return filedList;
    }

    /**
     * 查询字段配置
     *
     * @param id 主键ID
     * @return data
     */
    @Override
    public List<CrmModelFiledVO> queryField(Integer id) {
        CrmModel crmModel = queryById(id);
        if (id != null){
            List<JSONObject> customerList = new ArrayList<>();
            JSONObject customer = new JSONObject();
            customerList.add(customer.fluentPut("customerId", crmModel.get("customerId")).fluentPut("customerName", crmModel.get("customerName")));
            crmModel.put("customerId", customerList);
            crmModel.put("contractId", Collections.singletonList(new JSONObject().fluentPut("contractId",crmModel.get("contractId")).fluentPut("contractNum",crmModel.get("contractNum"))));

        }
        List<CrmModelFiledVO> vos = crmFieldService.queryField(crmModel);
        vos.removeIf(field -> field.getFieldName().equals("number"));

        vos.removeIf(field -> field.getFieldName().equals("ownerDeptId"));
        vos.removeIf(field -> field.getFieldName().equals("isRepetition"));
        vos.removeIf(field -> field.getFieldName().equals("courseSource"));
        vos.removeIf(field -> field.getFieldName().equals("source"));
        // 去除逾期状态
        vos.removeIf(field -> field.getFieldName().equals("overdueStatus"));
        vos.removeIf(field -> field.getFieldName().equals("periodsNum"));
        vos.removeIf(field -> field.getFieldName().equals("repayPeriods"));
        vos.removeIf(field -> field.getFieldName().equals("ownerOrderPool"));
        vos.removeIf(field -> field.getFieldName().equals("overdueTime"));
        vos.removeIf(field -> field.getFieldName().equals("billReturnType"));
        vos.removeIf(field -> field.getFieldName().equals("type"));
        vos.removeIf(field -> field.getFieldName().equals("studentId"));
        vos.removeIf(field -> field.getFieldName().equals("orderPoolStatus"));
        vos.removeIf(field -> field.getFieldName().equals("repaymentStatus"));
        vos.removeIf(field -> field.getFieldName().equals("checkTime"));
        vos.removeIf(field -> field.getFieldName().equals("repaymentDueMoney"));// 应还
        vos.removeIf(field -> field.getFieldName().equals("commissionMoney"));// 手续费
        vos.removeIf(field -> field.getFieldName().equals("repaymentDueDate"));// 应还款时间
        vos.removeIf(field -> field.getFieldName().equals("actualRepaymentDate"));// 实际还款时间
        vos.removeIf(field -> field.getFieldName().equals("collectionType"));// 回款类型
        vos.removeIf(field -> field.getFieldName().equals("studentStatus"));// 入学状态

        //继承字段在新增修改页面不显示
        QueryWrapper<CrmField> customerQueryWrapper = new QueryWrapper<>();
        customerQueryWrapper.eq("label", CrmEnum.CONTRACT.getType()).orderByAsc("sorting");
        customerQueryWrapper.ne("field_type", 1);
        List<CrmField> fields = crmFieldService.getBaseMapper().selectList(customerQueryWrapper);
        if(CollectionUtil.isNotEmpty(fields)){
            List<Integer> relevantIds = fields.stream().map(CrmField::getRelevant).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(relevantIds)){
                vos.removeIf(field -> relevantIds.contains(field.getFieldId()));
            }
        }
        return vos;
    }


    /**
     * 查询导入字段配置
     *
     * @param id 主键ID
     * @return data
     */
    public List<CrmModelFiledVO> queryExportField(Integer id) {
        //只导入三个字段
        CrmModel crmModel = queryById(id);
        List<JSONObject> customerList = new ArrayList<>();
        JSONObject customer = new JSONObject();
        customerList.add(customer.fluentPut("customerId", crmModel.get("customerId")).fluentPut("customerName", crmModel.get("customerName")));
        crmModel.put("contractId", Collections.singletonList(new JSONObject().fluentPut("contractId",crmModel.get("contractId")).fluentPut("contractNum",crmModel.get("contractNum"))));
        List<CrmModelFiledVO> filedVOList = new ArrayList<>();
        List<CrmModelFiledVO> vos = crmFieldService.queryField(crmModel);
//        vos.removeIf(field -> field.getFieldName().equals("number"));
        List<String> fields = Arrays.asList(new String[]{"contractNum","returnTime","money"});
        vos.removeIf(field -> !fields.contains(field.getFieldName()));
        CrmModelFiledVO vo = vos.stream().findFirst().get();
        CrmModelFiledVO contractNumVo = new CrmModelFiledVO();
        BeanUtil.copyProperties(vo,contractNumVo);
        contractNumVo.setValue(null);
        contractNumVo.setFieldName("contractNum");
        contractNumVo.setFieldId(null);
        contractNumVo.setType(1);
        contractNumVo.setName("合同编号");
        filedVOList.add(contractNumVo);
        filedVOList.addAll(vos);
        return filedVOList;
    }

    /**
     * 分页查询
     *
     * @param search
     * @return
     */
    @Override
    public BasePage<Map<String, Object>> queryPageList(CrmSearchBO search) {

        search.setLabel(CrmEnum.RECEIVABLES.getType());

        BasePage<Map<String, Object>> basePage = queryList(search);

        List<AdminDept> deptList = adminDeptService.list();

        Map<Integer,AdminDept> deptMap =  deptList.stream().collect(Collectors.toMap(AdminDept::getDeptId, v -> v, (p1, p2) -> p1));

        basePage.getList().forEach(map -> {
            //创建人名称回显
            if(ObjectUtil.isNotEmpty(map.get("createUserId"))){
                Long createUserId = Long.valueOf(String.valueOf(map.get("createUserId")));
                if(ObjectUtil.isNotEmpty(createUserId)){
                    String createUserName = UserCacheUtil.getUserName(createUserId);
                    map.put("createUserName",createUserName);
                }
            }

            // 负责人名称回显
            if(ObjectUtil.isNotEmpty(map.get("ownerUserId"))){
                Long ownerUserId = Long.valueOf(String.valueOf(map.get("ownerUserId")));
                if(ObjectUtil.isNotEmpty(ownerUserId)){
                    String ownerUserName = UserCacheUtil.getUserName(ownerUserId);
                    map.put("ownerUserName",ownerUserName);
                }
            }

            // 营销讲师名称回显
            if(ObjectUtil.isNotEmpty(map.get("teacherId"))){
                Long teacherId = Long.valueOf(String.valueOf(map.get("teacherId")));
                if(ObjectUtil.isNotEmpty(teacherId)){
                    String teacherName = UserCacheUtil.getUserName(teacherId);
                    map.put("teacherName",teacherName);
                }
            }

            //负责人所在部门
            if (ObjectUtil.isNotEmpty(map.get("ownerDeptId"))) {
                Long ownerDeptId = Long.valueOf(String.valueOf(map.get("ownerDeptId")));
                if (ObjectUtil.isNotEmpty(ownerDeptId)) {
                    String ownerDeptName = adminDeptService.queryAllDeptNameByDeptId(deptMap,Integer.valueOf(ownerDeptId.toString()));
                    map.put("ownerDeptName", ownerDeptName);
                }
            }


//            if(ObjectUtil.isNotEmpty(map.get("ownerOrderPool"))){
//                BillCrmOrderPool billCrmOrderPool = redis.get(Constants.ORG_ORDER_POOL+ OrgIdThreadLocal.getOrgId());
//                if(Optional.ofNullable(billCrmOrderPool).isPresent()){
//                    map.put("ownerOrderPoolName",billCrmOrderPool.getPoolName());
//                }
//            }

//            if(ObjectUtil.isNotEmpty(map.get("createDeptId"))){
//                Integer deptId = Integer.valueOf(String.valueOf(map.get("createDeptId")));
//                if(ObjectUtil.isNotEmpty(deptId)){
//                    String deptName = adminService.queryAllDeptNameByDeptId(deptId);
//                    map.put("createDeptName",deptName);
//                }
//            }

        });

        SearchRequest searchRequest = new SearchRequest(getIndex());
        searchRequest.types(getDocType());
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = createQueryBuilder(search);
        List<Integer> checkStatusList = new ArrayList<>();
        checkStatusList.add(1);
        checkStatusList.add(3);
        queryBuilder.must(QueryBuilders.termsQuery("checkStatus", checkStatusList));
//        queryBuilder.should(QueryBuilders.termQuery("checkStatus",1))
        sourceBuilder.query(queryBuilder);
        sourceBuilder.aggregation(AggregationBuilders.sum("receivablesMoney").field("money"));
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchCount = elasticsearchRestTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchCount.getAggregations();
            Map<String, Object> countMap = new HashMap<>();
            ParsedSum receivablesMoney = aggregations.get("receivablesMoney");
            countMap.put("receivablesMoney",receivablesMoney.getValue());
            basePage.setExtraData(new JSONObject().fluentPut("money",countMap));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return basePage;
    }

    /**
     * 查询字段配置
     * @param id 主键ID
     * @return data
     */
    @Override
    public CrmModel queryById(Integer id) {
        CrmModel crmModel;
        if (id != null) {
            crmModel = getBaseMapper().queryById(id, UserUtil.getUserId());
            crmModel.setLabel(CrmEnum.RECEIVABLES.getType());
            crmModel.setOwnerUserName(UserCacheUtil.getUserName(crmModel.getOwnerUserId()));
            crmModel.put("createUserName", UserCacheUtil.getUserName((Long) crmModel.get("createUserId")));
            if(BeanUtil.isNotEmpty(crmModel.get("crmDeptId"))){
                crmModel.put("ownerDeptName", this.adminService.queryDeptName(Integer.valueOf(String.valueOf(crmModel.get("ownerDeptId")))));
            }else{
                Integer deptId = UserCacheUtil.getUserInfo((Long)crmModel.get("ownerUserId")).getDeptId();
                crmModel.put("ownerDeptName", this.adminService.queryDeptName(deptId));
            }

//            if(Optional.ofNullable(crmModel.get("owner_order_pool")).isPresent()){
//                BillCrmOrderPool billCrmOrderPool = redis.get(Constants.ORG_ORDER_POOL+ OrgIdThreadLocal.getOrgId());
//                if(Optional.ofNullable(billCrmOrderPool).isPresent()){
//                    crmModel.put("ownerOrderPoolName",billCrmOrderPool.getPoolName());
//                }
//            }

            crmReceivablesDataService.setDataByBatchId(crmModel);
            List<String> stringList = SpringUtils.getBean(ICrmRoleFieldService.class).queryNoAuthField(crmModel.getLabel());
            List<String> deptFieldList = SpringUtils.getBean(ICrmDeptFieldService.class).queryNoAuthField(crmModel.getLabel());
            stringList = stringList.stream().filter(field -> deptFieldList.contains(field)).collect(Collectors.toList());

            stringList = stringList.stream().distinct().collect(Collectors.toList());
            stringList.forEach(crmModel::remove);
        } else {
            crmModel = new CrmModel(CrmEnum.RECEIVABLES.getType());
        }
        return crmModel;
    }


    /**
     * 查询字段配置
     * @param id 主键ID
     * @return data
     */
    @Override
    public CrmModel queryReturnTypeById(Integer id) {
        CrmModel crmModel;
        if (id != null) {
            crmModel = getBaseMapper().queryById(id, UserUtil.getUserId());
            crmModel.setLabel(CrmEnum.RECEIVABLES.getType());
            crmModel.setOwnerUserName(UserCacheUtil.getUserName(crmModel.getOwnerUserId()));
            crmModel.put("createUserName", UserCacheUtil.getUserName((Long) crmModel.get("createUserId")));
            if(BeanUtil.isNotEmpty(crmModel.get("crmDeptId"))){
                crmModel.put("ownerDeptName", this.adminService.queryDeptName(Integer.valueOf(String.valueOf(crmModel.get("ownerDeptId")))));
            }else{
                Integer deptId = UserCacheUtil.getUserInfo((Long)crmModel.get("ownerUserId")).getDeptId();
                crmModel.put("ownerDeptName", this.adminService.queryDeptName(deptId));
            }
            CrmReceivables crmReceivables = getBaseMapper().selectById(id);
            CrmContract crmContract = crmContractService.getById(crmReceivables.getContractId());
            if(Optional.ofNullable(crmContract).isPresent() && StringUtils.isNotBlank(crmContract.getReturnType())){
                crmModel.put("returnType", crmContract.getReturnType());
            }
            crmReceivablesDataService.setDataByBatchId(crmModel);
            List<String> stringList = SpringUtils.getBean(ICrmRoleFieldService.class).queryNoAuthField(crmModel.getLabel());
            List<String> deptFieldList = SpringUtils.getBean(ICrmDeptFieldService.class).queryNoAuthField(crmModel.getLabel());
            stringList = stringList.stream().filter(field -> deptFieldList.contains(field)).collect(Collectors.toList());

            stringList = stringList.stream().distinct().collect(Collectors.toList());
            stringList.forEach(crmModel::remove);
        } else {
            crmModel = new CrmModel(CrmEnum.RECEIVABLES.getType());
        }
        return crmModel;
    }

    /**
     * 保存或新增信息
     *
     * @param crmModel model
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdate(CrmContractSaveBO crmModel) {
        if(String.valueOf(crmModel.getEntity().get("ownerUserId")).split(",").length > 1){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_OWNER_USER_TOO_LONG);
        }
        //当分单销售数量大于1时抛出异常
        if(String.valueOf(crmModel.getEntity().get("salesUserId")).split(",").length > 1){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_SALES_USER_TOO_LONG);
        }
        if(String.valueOf(UserUtil.getUserId()).equals(String.valueOf(crmModel.getEntity().get("salesUserId")))){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_SALES_USER_CANNOT_MINE);
        }

        CrmReceivables crmReceivables = BeanUtil.copyProperties(crmModel.getEntity(), CrmReceivables.class);

        if(crmReceivables.getMoney().compareTo(new BigDecimal(0.00)) <= 0 || !Optional.ofNullable(crmReceivables.getMoney()).isPresent()){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_GT_ZERO);
        }

        crmReceivables.setRepaymentDueMoney(crmReceivables.getMoney());

        if(StringUtils.isEmpty(crmReceivables.getReturnType())){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_PAYMENT_DICT_SELECT);
        }

        CrmContract crmContract = crmContractService.getById(crmReceivables.getContractId());
        if (crmContract == null || !crmContract.getCheckStatus().equals(1)) {
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_ADD_ERROR);
        }

        if (crmReceivables.getReceivablesId() == null) {
            CrmModel contractModel = SpringUtils.getBean(ICrmContractService.class).queryById(crmReceivables.getContractId());
            QueryWrapper<CrmField> contractQueryWrapper = new QueryWrapper<>();
            contractQueryWrapper.eq("label", CrmEnum.CONTRACT.getType()).orderByAsc("sorting");
            contractQueryWrapper.ne("field_type", 1);
            List<CrmField> sourceFieldList = crmFieldService.getBaseMapper().selectList(contractQueryWrapper);

            QueryWrapper<CrmField> receivablesQueryWrapper = new QueryWrapper<>();
            receivablesQueryWrapper.eq("label", CrmEnum.RECEIVABLES.getType()).orderByAsc("sorting");
            receivablesQueryWrapper.ne("field_type", 1);
            List<CrmField> targeFieldList = crmFieldService.getBaseMapper().selectList(receivablesQueryWrapper);

            BeanExtendUtils im = new BeanExtendUtils(CrmContract.class, CrmReceivablesData.class);
            List<CrmModelFiledVO> receivablesDataList = im.copyVoList(sourceFieldList, targeFieldList, contractModel);
            crmModel.getField().addAll(receivablesDataList);
        }

        //购买课程
        if (StringUtils.isNotBlank(crmContract.getCourseSource())){
            crmReceivables.setCourseSource(crmContract.getCourseSource());
        }

        // 新增回款时,若合同存在VIP学员id,则更新到回款中
        if(crmContract.getStudentId() != null){
            crmReceivables.setStudentId(crmContract.getStudentId());
        }
        if(crmContract.getLeadsFormTime() != null){
            crmReceivables.setLeadsFormTime(crmContract.getLeadsFormTime());
        }

        if(StringUtils.isNotBlank(crmReceivables.getStudentsCall())){
            String telephone = crmReceivables.getStudentsCall();
            //验证电话格式
            if(!(telephone.matches(Const.REG_EXP_MOBILE) || telephone.matches(Const.REG_EXP_TELEPHONE))){
                throw new CrmException(CrmCodeEnum.CRM_REG_EXP_ERROR);
            }
        }

        if(BeanUtil.isEmpty(crmReceivables.getCreateUserId())){
            crmReceivables.setCreateUserId(UserUtil.getUserId());
        }

        if(ObjectUtil.isNotEmpty(crmReceivables.getPaymentTime())){
            // 应还款时间/实际还款时间
            crmReceivables.setRepaymentDueDate(crmReceivables.getPaymentTime());
            crmReceivables.setActualRepaymentDate(crmReceivables.getPaymentTime());
        }

        if(StringUtils.isBlank(crmReceivables.getReturnType())){
            crmReceivables.setReturnType(crmContract.getReturnType());
        }

        String batchId = StrUtil.isNotEmpty(crmReceivables.getBatchId()) ? crmReceivables.getBatchId() : IdUtil.simpleUUID();
        actionRecordUtil.updateRecord(crmModel.getField(), Dict.create().set("batchId", batchId).set("dataTableName", "bill_crm_business_data"));
        if (crmReceivables.getReceivablesId() == null) {

            CrmModel customerModel = SpringUtils.getBean(ICrmContractService.class).queryById(crmReceivables.getContractId());
            QueryWrapper<CrmField> customerQueryWrapper = new QueryWrapper<>();
            customerQueryWrapper.eq("label", CrmEnum.CONTRACT.getType()).orderByAsc("sorting");
            customerQueryWrapper.ne("field_type", 1);
            List<CrmField> sourceFieldList = crmFieldService.getBaseMapper().selectList(customerQueryWrapper);

            QueryWrapper<CrmField> receivablesQueryWrapper = new QueryWrapper<>();
            receivablesQueryWrapper.eq("label", CrmEnum.RECEIVABLES.getType()).orderByAsc("sorting");
            receivablesQueryWrapper.ne("field_type", 1);
            List<CrmField> targeFieldList = crmFieldService.getBaseMapper().selectList(receivablesQueryWrapper);

            BeanExtendUtils im = new BeanExtendUtils(CrmCustomer.class, CrmContractData.class);
            List<CrmModelFiledVO> receivablesDataList = im.copyVoList(sourceFieldList, targeFieldList, customerModel);
            crmModel.getField().addAll(receivablesDataList);
        }
        crmReceivablesDataService.saveData(crmModel.getField(), batchId);
        ExamineRecordSaveBO examineRecordSaveBO = crmModel.getExamineFlowData();

        ExamineRecordReturnVO examineData = null;

        boolean isUpdate = false;
        CrmReceivables oldReceivables = new CrmReceivables();
        if (crmReceivables.getReceivablesId() == null) {
            List<AdminConfigBo> configList = adminService.queryConfigByName("numberSetting");
            AdminConfigBo adminConfig = configList.stream().filter(config -> Objects.equals(getLabel().getType().toString(), config.getValue())).collect(Collectors.toList()).get(0);
            if (adminConfig.getStatus() == 1 && StrUtil.isEmpty(crmReceivables.getNumber())) {
                String result = crmNumberSettingService.generateNumber(adminConfig, null);
                if(BeanUtil.isEmpty(crmReceivables.getNumber())){
                    crmReceivables.setNumber(result);
                }
            }
            Integer count = lambdaQuery().eq(CrmReceivables::getNumber, crmReceivables.getNumber()).ne(CrmReceivables::getCheckStatus, 7).count();
            if (count != null && count > 0) {
                throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_NUM_ERROR);
            }
            if(BeanUtil.isEmpty(crmReceivables.getCreateTime())){
                crmReceivables.setCreateTime(DateUtil.date());
            }
            if(BeanUtil.isEmpty(crmReceivables.getUpdateTime())){
                crmReceivables.setUpdateTime(DateUtil.date());
            }
            crmReceivables.setBatchId(batchId);
//            crmReceivables.setOwnerUserId(UserUtil.getUserId());

            //负责人ID
            if(BeanUtil.isEmpty(crmReceivables.getOwnerUserId())){
                Object owner_user_id = crmModel.getEntity().get("owner_user_id");
                if (ObjectUtil.isAllNotEmpty(owner_user_id)){
                    crmReceivables.setOwnerUserId((Long) owner_user_id);
                }else{
                    crmReceivables.setOwnerUserId(UserUtil.getUserId());
                }
            }

            //设置数据来源
            CrmCustomer customer = crmCustomerService.getById(crmReceivables.getCustomerId());
            crmReceivables.setSource(customer.getSource());
            // 设置回款类别
            crmReceivables.setType(CrmBusinessConstEnum.账单类型_人工创建.getMsg());
            if(CrmBusinessConstEnum.账单类别_首付款合同.getMsg().equals(crmContract.getContractCategory())){
                crmReceivables.setCollectionType(CrmBusinessConstEnum.回款类型_首付款回款.getMsg());
            }else if(CrmBusinessConstEnum.账单类别_全款合同.getMsg().equals(crmContract.getContractCategory())){
                crmReceivables.setCollectionType(CrmBusinessConstEnum.回款类型_全额回款.getMsg());
            }else if(CrmBusinessConstEnum.账单类别_线下合同.getMsg().equals(crmContract.getContractCategory())){
                crmReceivables.setCollectionType(CrmBusinessConstEnum.回款类型_线下补款.getMsg());
            }
            crmReceivables.setRepaymentStatus(CrmRepaidStatusEnum.还款中.getRemarks());

            //是否重复
            crmReceivables.setIsRepetition(customer.getIsRepetition());
            // 初始入学状态
            crmReceivables.setStudentStatus(CrmBusinessConstEnum.入学状态_已入学.getMsg());

            //设置负责人所在部门
            if(ObjectUtil.isEmpty(crmReceivables.getOwnerUserId())){
                crmReceivables.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(UserUtil.getUserId()).getDeptId()));
            }else{
                crmReceivables.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(crmReceivables.getOwnerUserId()).getDeptId()));
            }

            save(crmReceivables);

            if ((crmReceivables.getCheckStatus() == null || crmReceivables.getCheckStatus() != 5)) {
                if (examineRecordSaveBO != null) {
                    this.supplementFieldInfo(2, crmReceivables.getReceivablesId(), null, examineRecordSaveBO);
                    examineRecordSaveBO.setTitle(crmReceivables.getNumber());
                    examineRecordSaveBO.setSubmitUserId(UserUtil.getUserId());
                    examineData = examineService.addExamineRecord(examineRecordSaveBO);
                    crmReceivables.setExamineRecordId(examineData.getRecordId());
                    crmReceivables.setCheckStatus(examineData.getExamineStatus());

                } else {
                    crmReceivables.setCheckStatus(1);
                    crmReceivables.setCheckTime(DateUtil.date());
                    crmReceivables.setRepaymentStatus(CrmRepaidStatusEnum.已还清.getRemarks());
                }

                QueryWrapper<CrmReceivables> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("contract_id", crmReceivables.getContractId());
                queryWrapper.in("check_status",1,3);
                List<CrmReceivables> receivables = getBaseMapper().selectList(queryWrapper);
                if(CollectionUtil.isNotEmpty(receivables)){
                    BigDecimal receivedMoney = receivables.stream().filter(item -> 1 == item.getCheckStatus() || 3 == item.getCheckStatus()).map(CrmReceivables::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                    receivedMoney = receivedMoney.add(crmReceivables.getMoney());
                    if(crmContract.getMoney().compareTo(receivedMoney) < 0){
                        throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_EXCEED);
                    }
                }else{
                    if(crmContract.getMoney().compareTo(crmReceivables.getMoney()) < 0){
                        throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_EXCEED);
                    }
                }

            }
            updateById(crmReceivables);

            if ((crmReceivables.getCheckStatus() == 1 || crmReceivables.getCheckStatus() == 3)) {
                //更新合同中已回款金额
                updateCustomerDeal(crmReceivables,true);
//                examineRecordService.updateContractMoney(crmReceivables.getReceivablesId());
            }
            CrmReceivablesPlan crmReceivablesPlan = crmReceivablesPlanService.getById(crmReceivables.getPlanId());
            if (crmReceivablesPlan != null) {
                crmReceivablesPlan.setReceivablesId(crmReceivables.getReceivablesId());
                crmReceivablesPlan.setUpdateTime(DateUtil.date());
                crmReceivablesPlanService.updateById(crmReceivablesPlan);
            }
            crmActivityService.addActivity(2, CrmActivityEnum.RECEIVABLES, crmReceivables.getReceivablesId());
            actionRecordUtil.addRecord(crmReceivables.getReceivablesId(), CrmEnum.RECEIVABLES, crmReceivables.getNumber());
        } else {
            isUpdate = true;
            CrmReceivables receivables = getById(crmReceivables.getReceivablesId());

            if(!"人工创建".equals(receivables.getType())){
                throw new CrmException(CrmCodeEnum.CRM_ORDER_NO_AUTH_UPDATE);
            }

            BeanUtils.copyProperties(receivables, oldReceivables);
            if (!receivables.getCreateUserId().equals(UserUtil.getUserId()) && examineRecordSaveBO != null) {
                throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_EDIT_ERROR);
            }
            if (receivables.getCheckStatus() == 1){
                throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_EXAMINE_PASS_ERROR);
            }
            if (receivables.getCheckStatus() != 4 && receivables.getCheckStatus() != 2 && receivables.getCheckStatus() != 5) {
                throw new CrmException(CrmCodeEnum.CRM_CONTRACT_EDIT_ERROR);
            }

            //设置负责人所在部门
            if(ObjectUtil.isEmpty(crmReceivables.getOwnerUserId())){
                crmReceivables.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(UserUtil.getUserId()).getDeptId()));
            }else{
                crmReceivables.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(crmReceivables.getOwnerUserId()).getDeptId()));
            }

            if ((crmReceivables.getCheckStatus() == null || crmReceivables.getCheckStatus() != 5)) {
                if (examineRecordSaveBO != null) {
                    this.supplementFieldInfo(2, receivables.getReceivablesId(), receivables.getExamineRecordId(), examineRecordSaveBO);
                    examineRecordSaveBO.setTitle(receivables.getNumber());
                    examineRecordSaveBO.setSubmitUserId(UserUtil.getUserId());
                    examineData = examineService.addExamineRecord(examineRecordSaveBO);
                    crmReceivables.setExamineRecordId(examineData.getRecordId());
                    crmReceivables.setCheckStatus(examineData.getExamineStatus());
                } else {
                    crmReceivables.setCheckStatus(1);
                    crmReceivables.setRepaymentStatus(CrmRepaidStatusEnum.已还清.getRemarks());
                }

                QueryWrapper<CrmReceivables> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("contract_id", crmReceivables.getContractId());
                queryWrapper.in("check_status",1,3);
                List<CrmReceivables> receivablesList = getBaseMapper().selectList(queryWrapper);
                if(CollectionUtil.isNotEmpty(receivablesList)){
                    BigDecimal receivedMoney = receivablesList.stream().filter(item -> 1 == item.getCheckStatus() || 3 == item.getCheckStatus()).map(CrmReceivables::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
                    receivedMoney = receivedMoney.add(crmReceivables.getMoney());
                    if(crmContract.getMoney().compareTo(receivedMoney) < 0){
                        throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_EXCEED);
                    }
                }else{
                    if(crmContract.getMoney().compareTo(crmReceivables.getMoney()) < 0){
                        throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_EXCEED);
                    }
                }

            }

            crmReceivables.setUpdateTime(DateUtil.date());
            crmReceivablesPlanService.update().eq("receivables_id", receivables.getReceivablesId()).set("receivables_id", null).update();
            CrmReceivablesPlan crmReceivablesPlan = crmReceivablesPlanService.getById(crmReceivables.getPlanId());
            if (crmReceivablesPlan != null) {
                crmReceivablesPlan.setReceivablesId(crmReceivables.getReceivablesId());
                crmReceivablesPlan.setUpdateTime(DateUtil.date());
                crmReceivablesPlanService.updateById(crmReceivablesPlan);
            }
            actionRecordUtil.updateRecord(BeanUtil.beanToMap(receivables), BeanUtil.beanToMap(crmReceivables), CrmEnum.CONTRACT, crmContract.getName(), crmContract.getContractId());
            updateById(crmReceivables);

//            if(StringUtils.isNotBlank(crmReceivables.getReturnType())){
//                CrmContract upCrmContract = new CrmContract();
//                upCrmContract.setContractId(crmContract.getContractId());
//                upCrmContract.setReturnType(crmReceivables.getReturnType());
//                updateContractReturnType(upCrmContract);
//            }

            crmReceivables = getById(crmReceivables.getReceivablesId());


            if((crmReceivables.getCheckStatus() == 1 || crmReceivables.getCheckStatus() == 3)){
                //根据合同Id获取合同下审核通过及审核中的回款金额
                BigDecimal sumMoney = baseMapper.querySumMoneyByContractId(crmReceivables.getContractId());
                //合同下回款审核通过及审核中金额大于等于500修改合同成交
                if(sumMoney.doubleValue() >= 1){
                    if(crmContract.getMoney().subtract(sumMoney).compareTo(BigDecimal.ZERO) <= 0){
                        crmContract.setBackStatus("已回款");
                    }else {
                        crmContract.setBackStatus("回款中");
                    }
                    crmContract.setReceivedMoney(sumMoney);
                    crmContract.setUninvoicedMonery(crmContract.getMoney().subtract(sumMoney));
                    updateContractDealStatus(crmContract,"已成交");
                }
            }
        }
        crmModel.setEntity(BeanUtil.beanToMap(crmReceivables));
        savePage(crmModel, crmReceivables.getReceivablesId(),false);
        //更新  客户成交状态
        if (crmReceivables.getCheckStatus() == 3) {
//            IS_DELETE = true;
            updateCustomerDeal(crmReceivables,true);
        }

        if(isUpdate){
            if(!ObjectUtil.equal(oldReceivables.getOwnerUserId(), crmReceivables.getOwnerUserId())){
                String ownerUserName = UserCacheUtil.getUserName(crmReceivables.getOwnerUserId());

                if(oldReceivables.getOwnerUserId() != null){
                    addMessage(oldReceivables.getNumber(),ownerUserName,oldReceivables.getOwnerUserId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_OWNER_USER.getType(),crmReceivables.getReceivablesId());
                }
                if(crmReceivables.getOwnerUserId() != null){
                    addMessage(oldReceivables.getNumber(),ownerUserName,crmReceivables.getOwnerUserId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_OWNER_USER.getType(),crmReceivables.getReceivablesId());
                }
            }

            if(!ObjectUtil.equal(oldReceivables.getTeacherId(), crmReceivables.getTeacherId())){
                String teacherName = UserCacheUtil.getUserName(crmReceivables.getTeacherId());

                if(oldReceivables.getTeacherId() != null){
                    addMessage(oldReceivables.getNumber(),teacherName,oldReceivables.getTeacherId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_TEACHER_USER.getType(),crmReceivables.getReceivablesId());
                }

                if(crmReceivables.getTeacherId() != null){
                    addMessage(oldReceivables.getNumber(),teacherName,crmReceivables.getTeacherId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_TEACHER_USER.getType(),crmReceivables.getReceivablesId());
                }
            }
        }

    }

    /**
     * 修改回款信息
     * @param crmReceivables
     */
    public void updateMoney(CrmReceivables crmReceivables){
        updateById(crmReceivables);
        Map<String, Object> data = BeanUtil.copyProperties(crmReceivables, HashMap.class);
        CrmContractSaveBO crmModel = new CrmContractSaveBO();
        List<CrmReceivablesData> dataList = SpringUtils.getBean(CrmReceivablesDataMapper.class).queryReceivablesDataByBatchId(crmReceivables.getBatchId());

        List<CrmModelFiledVO> crmModelFiledVOList = new ArrayList<>();
        for(int i=0;i<dataList.size();i++){
            CrmModelFiledVO c = new CrmModelFiledVO();
            c.setFieldId(dataList.get(i).getFieldId());
            c.setValue(dataList.get(i).getValue());
            c.setFieldName(dataList.get(i).getName());
            crmModelFiledVOList.add(c);
        }
        crmModel.setField(crmModelFiledVOList);
        crmModel.setEntity(data);
        savePage(crmModel, crmReceivables.getReceivablesId(),false);
    }

    /**
     * 新增回款
     * @param crmModelSaveBO
     */
    public void insertReceivables(CrmModelSaveBO crmModelSaveBO){
        String batchId = StrUtil.isNotEmpty(String.valueOf(crmModelSaveBO.getEntity().get("batchId"))) ? String.valueOf(crmModelSaveBO.getEntity().get("batchId")) : IdUtil.simpleUUID();
        crmReceivablesDataService.saveData(crmModelSaveBO.getField(), batchId);
        CrmReceivables crmReceivables = BeanUtil.copyProperties(crmModelSaveBO.getEntity(),CrmReceivables.class);
        crmReceivables.setBatchId(batchId);
        save(crmReceivables);
        savePage(crmModelSaveBO, crmReceivables.getReceivablesId(),false);

    }

    @Override
    public void setOtherField(Map<String, Object> map) {
        String customerName = crmCustomerService.getCustomerName((Integer) map.get("customerId"));
        map.put("customerName", customerName);
        CrmContract contract = crmContractService.queryContractById(Integer.valueOf(String.valueOf(map.get("contractId"))));
        if (contract != null) {
            map.put("contractNum", contract.getNum());
            map.put("contractMoney", contract.getMoney());
        }
        String ownerUserName = UserCacheUtil.getUserName((Long) map.get("ownerUserId"));
        map.put("ownerUserName", ownerUserName);
        String createUserName = UserCacheUtil.getUserName((Long) map.get("createUserId"));
        map.put("createUserName", createUserName);
        String deptName = "";
        if(BeanUtil.isNotEmpty(map.get("ownerDeptId"))){
            deptName = this.adminService.queryDeptName(Integer.valueOf(String.valueOf(map.get("ownerDeptId"))));
        }
        map.put("ownerDeptName",deptName);
        Integer planId = (Integer) map.get("planId");
        if (planId != null) {
            map.put("planNum", crmReceivablesPlanService.query().select("num").eq("plan_id", planId).one().getNum());
        }

        String teacherName = UserCacheUtil.getUserName((Long) map.get("teacherId"));
        map.put("teacherName",teacherName);

//        if(Optional.ofNullable(map.get("owner_order_pool")).isPresent()){
//            BillCrmOrderPool billCrmOrderPool = redis.get(Constants.ORG_ORDER_POOL+ OrgIdThreadLocal.getOrgId());
//            if(Optional.ofNullable(billCrmOrderPool).isPresent()){
//                map.put("ownerOrderPoolName",billCrmOrderPool.getPoolName());
//            }
//        }

    }

    @Override
    public Dict getSearchTransferMap() {
        return Dict.create()
                .set("customerId", "customerName").set("contractId", "contractNum").set("planId","planNum");
    }

    /**
     * 删除回款数据
     *
     * @param ids ids
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByIds(List<Integer> ids) {
        Integer count = crmReceivablesPlanService.lambdaQuery().in(CrmReceivablesPlan::getReceivablesId, ids).count();
        if (count != 0) {
            throw new CrmException(CrmCodeEnum.CRM_DATA_JOIN_ERROR);
        }
        List<CrmReceivables> receivablesList = lambdaQuery().in(CrmReceivables::getReceivablesId, ids).ne(CrmReceivables::getCheckStatus, 7).list();
        for(CrmReceivables receivables : receivablesList){
            if(!"人工创建".equals(receivables.getType())){
                throw new CrmException(CrmCodeEnum.CRM_ORDER_NO_AUTH_DELETE);
            }
            if(ObjectUtil.isNotEmpty(receivables.getStudentId())){
                if(!CrmBusinessConstEnum.回款类型_线下补款.getMsg().equals(receivables.getCollectionType())){
                    Integer studentCount = crmStudentService.lambdaQuery().ne(CrmStudent::getStatus, 3).eq(CrmStudent::getStudentId, receivables.getStudentId()).count();
                    if (studentCount > 0) {
                        throw new CrmException(CrmCodeEnum.CRM_DATA_JOIN_ERROR);
                    }
                }
            }
        }

        for (Integer id : ids) {
            CrmReceivables receivables = getById(id);
            boolean bol = (receivables.getCheckStatus() != 4 && receivables.getCheckStatus() != 5) && ! (UserUtil.isAdmin());
            if (bol) {
                throw new CrmException(CrmCodeEnum.CAN_ONLY_DELETE_WITHDRAWN_AND_SUBMITTED_EXAMINE);
            }

            /*if (receivables.getCheckStatus() == 1 || receivables.getCheckStatus() == 3) {
                examineRecordService.updateUnreceivedMoney(id);
                //是否需要更新合同成交状态
                changeCustomerStatus(receivables);
                //还原合同金额
            }*/
            //删除跟进记录
            crmActivityService.deleteActivityRecord(CrmActivityEnum.RECEIVABLES, Collections.singletonList(id));
            //删除字段操作记录
            crmActionRecordService.deleteActionRecord(CrmEnum.RECEIVABLES, Collections.singletonList(receivables.getReceivablesId()));

            //删除自定义字段
            crmReceivablesDataService.deleteByBatchId(Collections.singletonList(receivables.getBatchId()));
            //删除文件
            adminFileService.delete(Collections.singletonList(receivables.getBatchId()));
            if (ObjectUtil.isNotEmpty(receivables.getExamineRecordId())) {
                examineService.deleteExamineRecord(receivables.getExamineRecordId());
            }
//            IS_DELETE = false;
            //埋点更新合同 现金已回款金额 全额贷已回款金额 分期已回款金额 全额贷代偿金额
            updateContractMoney(receivables);
            receivables.setCheckStatus(7);
            updateById(receivables);

            //更新客户回款状态
            if(receivables.getCheckStatus() != 2 && receivables.getCheckStatus() != 4 && receivables.getCheckStatus() != 5){
                updateCustomerDeal(receivables,false);
            }else{
                updateCustomerDeal(receivables,false);
            }
        }
        deletePage(ids);
    }

    /**
     * 修改回款负责人
     *
     * @param receivablesIds 回款id列表
     * @param newOwnerUserId 新负责人ID
     */
    @Override
    public void changeOwnerUser(List<Integer> receivablesIds, Long newOwnerUserId) {

        Integer deptId = UserCacheUtil.getUserInfo(newOwnerUserId).getDeptId();
        String ownerDeptName = adminService.queryDeptName(deptId);

        QueryWrapper<CrmReceivables> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("receivables_id", receivablesIds);
        queryWrapper.notIn("check_status", 7);
        List<CrmReceivables> crmReceivablesList = query().getBaseMapper().selectList(queryWrapper);

        LambdaUpdateWrapper<CrmReceivables> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(CrmReceivables::getReceivablesId, receivablesIds);
        wrapper.set(CrmReceivables::getOwnerUserId, newOwnerUserId);
        wrapper.set(CrmReceivables::getOwnerDeptId, String.valueOf(deptId));
        update(wrapper);
        for (Integer id : receivablesIds) {
            actionRecordUtil.addConversionRecord(id,CrmEnum.RECEIVABLES,newOwnerUserId,getById(id).getNumber());
        }
        //修改es
        Map<String, Object> map = new HashMap<>();
        map.put("ownerUserId", newOwnerUserId);
        map.put("ownerDeptId", deptId);
        map.put("ownerDeptName", ownerDeptName);
        updateField(map, receivablesIds);

//        updateField("ownerUserId", newOwnerUserId, receivablesIds);
//        updateField("ownerDeptId", deptId, receivablesIds);
//        updateField("ownerDeptName", ownerDeptName, receivablesIds);

        String ownerUserName = UserCacheUtil.getUserName(newOwnerUserId);
        for(CrmReceivables receivables : crmReceivablesList){
            if(!ObjectUtil.equal(receivables.getOwnerUserId(),newOwnerUserId)){
                if((!UserUtil.getUserId().equals(receivables.getOwnerUserId())) && (receivables.getOwnerUserId() != null)){
                    addMessage(receivables.getNumber(),ownerUserName,receivables.getOwnerUserId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_OWNER_USER.getType(),receivables.getReceivablesId());
                }

                if((!UserUtil.getUserId().equals(newOwnerUserId)) && newOwnerUserId != null){
                    addMessage(receivables.getNumber(),ownerUserName,newOwnerUserId,AdminMessageEnum.CRM_RECEIVABLES_CHANGE_OWNER_USER.getType(),receivables.getReceivablesId());
                }
            }
        }
    }

    /**
     * 修改回款讲师负责人
     * @param ownerUserBO
     */
    @Override
    public void changeTeacherUser(CrmChangeOwnerUserBO ownerUserBO){
        QueryWrapper<CrmReceivables> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("receivables_id", ownerUserBO.getIds());
        queryWrapper.notIn("check_status", 7);
        List<CrmReceivables> crmReceivablesList = query().getBaseMapper().selectList(queryWrapper);

        LambdaUpdateWrapper<CrmReceivables> wrapper = new LambdaUpdateWrapper<>();
        wrapper.in(CrmReceivables::getReceivablesId, ownerUserBO.getIds());
        wrapper.set(CrmReceivables::getTeacherId, ownerUserBO.getTeacherId());
        update(wrapper);

        String teacherName = UserCacheUtil.getUserName(ownerUserBO.getTeacherId());

        // 操作记录
        for (Integer id : ownerUserBO.getIds()) {
            actionRecordUtil.conversionTeacherRecordAdd(id,CrmEnum.RECEIVABLES,ownerUserBO.getTeacherId(),getById(id).getNumber());
        }

        //修改es
        Map<String, Object> map = new HashMap<>();
        map.put("teacherId", ownerUserBO.getTeacherId());
        map.put("teacherName", teacherName);
        updateField(map, ownerUserBO.getIds());

        // 发送消息
        for(CrmReceivables receivables : crmReceivablesList){
            if(!ObjectUtil.equal(receivables.getTeacherId(),ownerUserBO.getTeacherId())){
                if((!UserUtil.getUserId().equals(receivables.getTeacherId())) && (receivables.getTeacherId() != null)){
                    addMessage(receivables.getNumber(),teacherName,receivables.getTeacherId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_TEACHER_USER.getType(),receivables.getReceivablesId());
                }

                if((!UserUtil.getUserId().equals(ownerUserBO.getTeacherId())) && ownerUserBO.getTeacherId() != null){
                    addMessage(receivables.getNumber(),teacherName,ownerUserBO.getTeacherId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_TEACHER_USER.getType(),receivables.getReceivablesId());
                }
            }
        }
    }

    /**
     * 导出
     *
     * @param response resp
     * @param search   搜索对象
     */
    @Override
    public void exportExcel(HttpServletResponse response, CrmSearchBO search) {
        List<Map<String, Object>> dataList = queryPageList(search).getList();
        try (ExcelWriter writer = ExcelUtil.getWriter()) {
            List<CrmFieldSortVO> headList = crmFieldService.queryListHead(getLabel().getType());
            headList.forEach(head -> writer.addHeaderAlias(head.getFieldName(), head.getName()));
            writer.merge(headList.size() - 1, "回款信息");
            if (dataList.size() == 0) {
                Map<String, Object> record = new HashMap<>();
                headList.forEach(head -> record.put(head.getFieldName(), ""));
                dataList.add(record);
            }
            dataList.forEach(record -> {
                if (record.get("checkStatus") == null || "".equals(record.get("checkStatus"))) {
                    return;
                }else{
                    String checkStatus;
                    //0待审核、1通过、2拒绝、3审核中 4:撤回 5 未提交
                    switch ((Integer) record.get("checkStatus")) {
                        case 1:
                            checkStatus = "通过";
                            break;
                        case 2:
                            checkStatus = "拒绝";
                            break;
                        case 3:
                            checkStatus = "审核中";
                            break;
                        case 4:
                            checkStatus = "撤回";
                            break;
                        case 5:
                            checkStatus = "未提交";
                            break;
                        case 7:
                            checkStatus = "已删除";
                            break;
                        default:
                            checkStatus = "待审核";
                    }
                    record.put("checkStatus", checkStatus);
                }

                if(record.get("categories") != null){
                    String categories = "";
                    if(Integer.valueOf(1).equals(record.get("categories"))){
                        categories = "电商美工";
                    }else if(Integer.valueOf(2).equals(record.get("categories"))){
                        categories = "手绘插画";
                    }else if(Integer.valueOf(3).equals(record.get("categories"))){
                        categories = "影视后期";
                    }
                    record.put("categories", categories);
                }

                if(record.get("salesType") != null){
                    String salesType = "";
                    if(Integer.valueOf(1).equals(record.get("salesType"))){
                        salesType = "电销";
                    }else if(Integer.valueOf(2).equals(record.get("salesType"))){
                        salesType = "网销";
                    }
                    record.put("salesType", salesType);
                }




            });
            writer.setOnlyAlias(true);
            writer.write(dataList, true);
            writer.setRowHeight(0, 20);
            writer.setRowHeight(1, 20);
            for (int i = 0; i < headList.size(); i++) {
                writer.setColumnWidth(i, 20);
            }
            Cell cell = writer.getCell(0, 0);
            CellStyle cellStyle = cell.getCellStyle();
            cellStyle.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
            cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            Font font = writer.createFont();
            font.setBold(true);
            font.setFontHeightInPoints((short) 16);
            cellStyle.setFont(font);
            cell.setCellStyle(cellStyle);
            //自定义标题别名
            //response为HttpServletResponse对象
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
            String fileName = "回款" + DateUtils.dateTimeNow() + ".xls";
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out);

            // 新增消息
            addMessage(String.valueOf(dataList.size()),"导出数据" + String.valueOf(dataList.size()) + "条",UserUtil.getUserId(),AdminMessageEnum.CRM_RECEIVABLES_EXPORT.getType(),null);

        } catch (Exception e) {
            log.error("导出回款错误：", e);
        }
    }

    /**
     * 查询文件数量
     *
     * @param id id
     * @return data
     */
    @Override
    public CrmInfoNumVO num(Integer id) {
        List<String> batchIdList = new ArrayList<>();
        CrmReceivables crmReceivables = getById(id);
        AdminFileService fileService = SpringUtils.getBean(AdminFileService.class);
        List<CrmField> crmFields = crmFieldService.queryFileField();
        if (crmFields.size() > 0) {
            LambdaQueryWrapper<CrmReceivablesData> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(CrmReceivablesData::getValue);
            wrapper.eq(CrmReceivablesData::getBatchId, crmReceivables.getBatchId());
            wrapper.in(CrmReceivablesData::getFieldId, crmFields.stream().map(CrmField::getFieldId).collect(Collectors.toList()));
            batchIdList.addAll(crmReceivablesDataService.listObjs(wrapper, Object::toString));
            batchIdList.add(crmReceivables.getEnclosure());
        }
        if(StringUtils.isNotBlank(crmReceivables.getBatchId())){
            batchIdList.add(crmReceivables.getBatchId());
        }
        CrmInfoNumVO numVO = new CrmInfoNumVO();
        numVO.setFileCount(fileService.queryNum(batchIdList));
        return numVO;
    }

    /**
     * 查询文件列表
     *
     * @param id id
     * @return file
     */
    @Override
    public List<FileEntity> queryFileList(Integer id) {
        List<FileEntity> fileEntityList = new ArrayList<>();
        CrmReceivables crmReceivables = getById(id);
        AdminFileService fileService = SpringUtils.getBean(AdminFileService.class);
        fileService.queryFileList(crmReceivables.getBatchId()).forEach(fileEntity -> {
            fileEntity.setSource("附件上传");
            fileEntity.setReadOnly(0);
            fileEntityList.add(fileEntity);
        });
        List<CrmField> crmFields = crmFieldService.queryFileField();
        if (crmFields.size() > 0) {
            LambdaQueryWrapper<CrmReceivablesData> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(CrmReceivablesData::getValue);
            wrapper.eq(CrmReceivablesData::getBatchId, crmReceivables.getBatchId());
            wrapper.in(CrmReceivablesData::getFieldId, crmFields.stream().map(CrmField::getFieldId).collect(Collectors.toList()));
            List<FileEntity> data = fileService.queryFileList(crmReceivablesDataService.listObjs(wrapper, Object::toString));
            data.forEach(fileEntity -> {
                fileEntity.setSource("回款详情");
                fileEntity.setReadOnly(1);
                fileEntityList.add(fileEntity);
            });
        }

        if(StringUtils.isNotBlank(crmReceivables.getEnclosure())){
            fileService.queryFileList(crmReceivables.getEnclosure()).forEach(fileEntity -> {
                fileEntity.setSource("回款审批");
                fileEntity.setReadOnly(1);
                fileEntityList.add(fileEntity);
            });
        }
        return fileEntityList;
    }

    @Override
    public List<CrmModelFiledVO> information(Integer contractId) {
        CrmModel crmModel = queryById(contractId);
        Set<String> set  = crmModel.keySet();
        List<String> keyList = new ArrayList<>(set);

        List<String> systemFieldList = Arrays.asList("checkStatus","checkTime","periodsNum","repayPeriods","type","trainingPeriods","repaymentStatus","overdueTime",
                "billReturnType","enclosure","createUserName","ownerDeptId", "createTime", "updateTime", "lastTime", "receivedMoney", "unreceivedMoney");

        List<CrmModelFiledVO> crmModelFiledVOS = queryInformation(crmModel, keyList);

        CrmModelFiledVO customerField = crmModelFiledVOS.stream().filter(item -> "customerId".equals(item.getFieldName())).collect(Collectors.toList()).get(0);
        CrmModelFiledVO contractField = crmModelFiledVOS.stream().filter(item -> "contractId".equals(item.getFieldName())).collect(Collectors.toList()).get(0);

        crmModelFiledVOS.removeIf(item -> Arrays.asList("contractId","ownerDeptId","customerId").contains(item.getFieldName()));

        crmModelFiledVOS.add(new CrmModelFiledVO().setFieldName("checkStatus").setName("审核状态").setValue(crmModel.get("checkStatus")).setFormType("check_status").setFieldType(1));
        crmModelFiledVOS.add(contractField.getSorting(),new CrmModelFiledVO().setFieldName("contractId").setName("合同编号").setValue(new JSONObject().fluentPut("contractId", crmModel.get("contractId")).fluentPut("contractNum", crmModel.get("contractNum"))).setFormType("contract").setFieldType(1));
        crmModelFiledVOS.add(contractField.getSorting(),new CrmModelFiledVO().setFieldName("contractId").setName("合同名称").setValue(new JSONObject().fluentPut("contractId", crmModel.get("contractId")).fluentPut("contractNum", crmModel.get("contractName"))).setFormType("contract").setFieldType(1));
        crmModelFiledVOS.add(customerField.getSorting(),new CrmModelFiledVO().setFieldName("customerId").setName("学员名称").setValue(new JSONObject().fluentPut("customerId", crmModel.get("customerId")).fluentPut("customerName", crmModel.get("customerName"))).setFormType("customer").setFieldType(1));
        crmModelFiledVOS.add(new CrmModelFiledVO().setFieldName("ownerDeptId").setName("负责人所在部门").setValue(new JSONObject().fluentPut("ownerDeptId", crmModel.get("ownerDeptId")).fluentPut("ownerDeptName", crmModel.get("ownerDeptName"))).setAuthLevel(2).setFieldType(1));
//        crmModelFiledVOS.add(new CrmModelFiledVO().setFieldName("planId").setName("期数").setValue(crmModel.get("planNum")).setFormType("planNum").setFieldType(FieldEnum.NUMBER.getType()));
        List<CrmModelFiledVO> filedVOS = crmModelFiledVOS.stream().sorted(Comparator.comparingInt(r -> -r.getFieldType())).peek(r -> {
            r.setFieldType(null);
            r.setSetting(null);
            r.setType(null);
            r.setAuthLevel(2);
            if (systemFieldList.contains(r.getFieldName())) {
                r.setSysInformation(1);
            } else {
                r.setSysInformation(0);
            }
        }).collect(Collectors.toList());

        List<String> removeField = Arrays.asList("");
        filedVOS.removeIf(item -> removeField.contains(item.getFieldName()));

        return filedVOS;
    }


    @Override
    public void updateInformation(CrmUpdateInformationBO updateInformationBO) {
        String batchId = updateInformationBO.getBatchId();
        Integer receivablesId = updateInformationBO.getId();
        Integer examineCount = crmExamineService.queryCount(getLabel());
        CrmReceivables receivables = getById(receivablesId);
        if (!receivables.getCreateUserId().equals(UserUtil.getUserId()) && examineCount > 0) {
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_EDIT_ERROR);
        }
        if (receivables.getCheckStatus() == 1){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_EXAMINE_PASS_ERROR);
        }
        if (receivables.getCheckStatus() != 4 && receivables.getCheckStatus() != 2 && receivables.getCheckStatus() != 5) {
            throw new CrmException(CrmCodeEnum.CRM_CONTRACT_EDIT_ERROR);
        }
        updateInformationBO.getList().forEach(record -> {
            CrmReceivables oldReceivables = getById(updateInformationBO.getId());
            Map<String, Object> oldReceivablesMap = BeanUtil.beanToMap(oldReceivables);
            if (record.getInteger("fieldType") == 1) {
                Map<String, Object> crmReceivablesMap = new HashMap<>(oldReceivablesMap);
                crmReceivablesMap.put(record.getString("fieldName"), record.get("value"));
                CrmReceivables crmReceivables = BeanUtil.mapToBean(crmReceivablesMap, CrmReceivables.class, true);
                if(StringUtils.isNotBlank(crmReceivables.getStudentsCall())){
                    String telephone = crmReceivables.getStudentsCall();
                    //验证电话格式
                    if(!(telephone.matches(Const.REG_EXP_MOBILE) || telephone.matches(Const.REG_EXP_TELEPHONE))){
                        throw new CrmException(CrmCodeEnum.CRM_REG_EXP_ERROR);
                    }
                }

                if("teacherId".equals(record.getString("fieldName"))){
                    String teacherName = UserCacheUtil.getUserName(record.getLong("value"));
                    if((!UserUtil.getUserId().equals(oldReceivables.getTeacherId())) && (oldReceivables.getTeacherId() != null)){
                        addMessage(oldReceivables.getNumber(),teacherName,oldReceivables.getTeacherId(),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_TEACHER_USER.getType(),crmReceivables.getReceivablesId());
                    }

                    if(record.getLong("value") != null){
                        addMessage(oldReceivables.getNumber(),teacherName,record.getLong("value"),AdminMessageEnum.CRM_RECEIVABLES_CHANGE_TEACHER_USER.getType(),crmReceivables.getReceivablesId());
                    }
                }

                if("money".equals(record.getString("fieldName"))){

                    if(new BigDecimal(String.valueOf(record.get("value"))).compareTo(new BigDecimal(0.00)) <= 0 || !Optional.ofNullable(record.get("value")).isPresent()){
                        throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_GT_ZERO);
                    }

                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("fieldName","repayment_due_money");
                    jsonObject.put("value",record.get("value"));
                    jsonObject.put("type",6);
                    jsonObject.put("fieldType",1);
                    update().set(StrUtil.toUnderlineCase("repayment_due_money"), record.get("value")).eq("receivables_id",updateInformationBO.getId()).update();
                    updateField(jsonObject, receivablesId);
                    getRestTemplate().refresh(getIndex());
                }

                if("paymentTime".equals(record.getString("fieldName"))){
                    JSONObject repaymentDueDate = new JSONObject();
                    repaymentDueDate.put("fieldName","repayment_due_date");
                    repaymentDueDate.put("value",record.get("value"));
                    repaymentDueDate.put("type",6);
                    repaymentDueDate.put("fieldType",1);
                    update().set(StrUtil.toUnderlineCase("repayment_due_date"), record.get("value")).eq("receivables_id",updateInformationBO.getId()).update();
                    updateField(repaymentDueDate, receivablesId);
                    getRestTemplate().refresh(getIndex());

                    JSONObject actualRepaymentDate = new JSONObject();
                    actualRepaymentDate.put("fieldName","actual_repayment_date");
                    actualRepaymentDate.put("value",record.get("value"));
                    actualRepaymentDate.put("type",6);
                    actualRepaymentDate.put("fieldType",1);
                    update().set(StrUtil.toUnderlineCase("actual_repayment_date"), record.get("value")).eq("receivables_id",updateInformationBO.getId()).update();
                    updateField(actualRepaymentDate, receivablesId);
                    getRestTemplate().refresh(getIndex());
                }

                actionRecordUtil.updateRecord(oldReceivablesMap, crmReceivablesMap, CrmEnum.RECEIVABLES, crmReceivables.getNumber(), crmReceivables.getReceivablesId());
                update().set(StrUtil.toUnderlineCase(record.getString("fieldName")), record.get("value")).eq("receivables_id",updateInformationBO.getId()).update();
            } else if (record.getInteger("fieldType") == 0 || record.getInteger("fieldType") == 2) {

                CrmReceivablesData receivablesData = crmReceivablesDataService.lambdaQuery().select(CrmReceivablesData::getValue).eq(CrmReceivablesData::getFieldId, record.getInteger("fieldId"))
                        .eq(CrmReceivablesData::getBatchId, batchId).one();
                String value = receivablesData != null ? receivablesData.getValue() : null;
                String detail = actionRecordUtil.getDetailByFormTypeAndValue(record,value);
                actionRecordUtil.publicContentRecord(CrmEnum.RECEIVABLES, BehaviorEnum.UPDATE, receivablesId, oldReceivables.getNumber(), detail);
                boolean isUpdate = false;
                if ((null == value && null == record.get("value"))) {
                    isUpdate = false;
                } else if (null != value && !value.equals(String.valueOf(record.get("value")))) {
                    isUpdate = true;
                } else if (null != record.get("value") && !String.valueOf(record.get("value")).equals(value)) {
                    isUpdate = true;
                }

                if(isUpdate){
                    boolean bol = crmReceivablesDataService.lambdaUpdate()
                            .set(CrmReceivablesData::getName,record.getString("fieldName"))
                            .set(CrmReceivablesData::getValue, record.getString("value"))
                            .eq(CrmReceivablesData::getFieldId, record.getInteger("fieldId"))
                            .eq(CrmReceivablesData::getBatchId, batchId).update();
                    if (!bol) {
                        CrmReceivablesData crmReceivabelsData = new CrmReceivablesData();
                        crmReceivabelsData.setFieldId(record.getInteger("fieldId"));
                        crmReceivabelsData.setName(record.getString("fieldName"));
                        crmReceivabelsData.setValue(record.getString("value"));
                        crmReceivabelsData.setCreateTime(new Date());
                        crmReceivabelsData.setBatchId(batchId);
                        crmReceivablesDataService.save(crmReceivabelsData);
                    }
                }
            }
            updateField(record, receivablesId);
        });
    }

    @Override
    public BasePage<JSONObject> queryListByContractId(BasePage<JSONObject> page, Integer contractId, String conditions) {
        BasePage<JSONObject> jsonObjects = getBaseMapper().queryListByContractId(page,contractId, conditions);
        for (JSONObject jsonObject : jsonObjects.getList()) {
            Long ownerUserId = jsonObject.getLong("ownerUserId");
            String ownerUserName = UserCacheUtil.getUserName(ownerUserId);
            jsonObject.put("ownerUserName",ownerUserName);
        }
        return jsonObjects;
    }

    /**
     * 更新客户下所有合同为未成交状态
     * @param crmContractList
     */
    public void changeContractUnDeal(List<CrmContract> crmContractList){

        for (CrmContract contract : crmContractList) {
            contract.setDealStatus("未成交");
            contract.setDealTime(null);
            contract.setReceivedMoney(new BigDecimal(0));
            contract.setUnreceivedMoney(contract.getMoney());
            contract.setRecentBackTime(null);
            SpringUtils.getBean(ICrmContractService.class).updateById(contract);
            // 更新合同ES
            String index = CrmEnum.CONTRACT.getIndex();
            BulkRequest bulkRequest = new BulkRequest();
            UpdateRequest updateRequest = new UpdateRequest(index, "_doc", String.valueOf(contract.getContractId()));
            Map<String, Object> map = new HashMap<>();
            map.put("dealStatus",contract.getDealStatus());
            map.put("dealTime",contract.getDealTime());
            map.put("receivedMoney",contract.getReceivedMoney());
            map.put("unreceivedMoney",contract.getUnreceivedMoney());
            map.put("repaymentStatus", contract.getRepaymentStatus());
            map.put("recentBackTime", contract.getRecentBackTime());
            updateRequest.doc(map);
            bulkRequest.add(updateRequest);
            try {
                elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
                elasticsearchRestTemplate.refresh(index);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 回款记录  更新客户成交状态
     * @param receivables
     * @param changeData  是否更新VIP成交状态
     */
    @Override
//    @Transactional(rollbackFor = Exception.class)
    public void updateCustomerDeal(CrmReceivables receivables,boolean changeData){
        try {
            Integer customerId  = receivables.getCustomerId();
            if(ObjectUtil.isEmpty(customerId)){
                return;
            }
            QueryWrapper<CrmReceivables> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("customer_id", customerId);
            queryWrapper.and(wrapper -> wrapper.eq("check_status", 1).or().eq("check_status", 3));
            List<CrmReceivables> crmReceivablesList = query().getBaseMapper().selectList(queryWrapper);

            //查询客户下所有合同
            QueryWrapper<CrmContract> crmContractWrapper = new QueryWrapper<>();
            crmContractWrapper.eq("customer_id",customerId);
            crmContractWrapper.and(wrapper -> wrapper.eq("check_status",1));
            List<CrmContract> crmContractList = crmContractService.list(crmContractWrapper);

            //查询客户下所有退款
            QueryWrapper<CrmRefund> crmRefundQueryWrapper = new QueryWrapper<>();
            crmRefundQueryWrapper.eq("customer_id",customerId);
            crmRefundQueryWrapper.and(wrapper -> wrapper.eq("check_status", 1).or().eq("check_status", 3));
            List<CrmRefund> crmRefundList = crmReFundService.list(crmRefundQueryWrapper);

            if(CollectionUtil.isEmpty(crmReceivablesList)){

                LambdaUpdateWrapper<CrmCustomer> wrapper = new LambdaUpdateWrapper<>();
                wrapper.set(CrmCustomer::getVipDealStatus, "未成交");
                wrapper.set(CrmCustomer::getVipDealTime, null);
                wrapper.set(CrmCustomer::getStudentStatus, null);
                wrapper.set(CrmCustomer::getRepaymentStatus, null);
                wrapper.in(CrmCustomer::getCustomerId, customerId);
                SpringUtils.getBean(ICrmCustomerService.class).update(wrapper);


                CrmCustomer byId = SpringUtils.getBean(ICrmCustomerService.class).getById(customerId);
//                byId.setVipDealStatus("未成交");
//                byId.setVipDealTime(null);
//                SpringUtils.getBean(ICrmCustomerService.class).updateById(byId);

                //更新客户ES
                BulkRequest bulkRequest = new BulkRequest();
                UpdateRequest updateRequest = new UpdateRequest(CrmEnum.CUSTOMER.getIndex(), "_doc", String.valueOf(customerId));
                Map<String, Object> map = new HashMap<>();
                map.put("vipDealStatus","未成交");
                map.put("vipDealTime",null);
                map.put("studentStatus",null);
                map.put("repaymentStatus",null);
                updateRequest.doc(map);
                bulkRequest.add(updateRequest);
                try {
                    elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
                    elasticsearchRestTemplate.refresh(CrmEnum.CUSTOMER.getIndex());
                } catch (IOException e) {
                    e.printStackTrace();
                }

                String leadsIndex = CrmEnum.LEADS.getIndex();
                CrmLeads crmLeads = SpringUtils.getBean(ICrmLeadsService.class).queryLeadsDataBySerialNumber(byId.getSerialNumber());
                if(BeanUtil.isNotEmpty(crmLeads)){
                    LambdaUpdateWrapper<CrmLeads> wrapper1 = new LambdaUpdateWrapper<>();
                    wrapper1.set(CrmLeads::getVipDealStatus, "未成交");
                    wrapper1.set(CrmLeads::getVipDealTime, null);
                    wrapper1.in(CrmLeads::getLeadsId, crmLeads.getLeadsId());
                    SpringUtils.getBean(ICrmLeadsService.class).update(wrapper1);

                    BulkRequest vipLeadsBulkRequest = new BulkRequest();
                    UpdateRequest vipLeadsUpdateRequest = new UpdateRequest(leadsIndex, "_doc", String.valueOf(crmLeads.getLeadsId()));
                    Map<String, Object> mapLeads = new HashMap<>();
                    mapLeads.put("vipDealStatus", "未成交");
                    mapLeads.put("vipDealTime", null);
                    vipLeadsUpdateRequest.doc(mapLeads);
                    vipLeadsBulkRequest.add(vipLeadsUpdateRequest);
                    try {
                        elasticsearchRestTemplate.getClient().bulk(vipLeadsBulkRequest, RequestOptions.DEFAULT);
                        elasticsearchRestTemplate.refresh(leadsIndex);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                crmContractList.forEach(item -> {
                    item.setRepaymentStatus(null);
                });

                //TODO 更新合同信息为未成交
                changeContractUnDeal(crmContractList);
                return;
            }

            CrmContract contractById = crmContractService.queryContractById(receivables.getContractId());
            if(CrmBusinessConstEnum.账单类别_首付款合同.getMsg().equals(contractById.getContractCategory())){
                Map<Integer, List<CrmReceivables>> receivablesMap = crmReceivablesList.stream().collect(Collectors.groupingBy(CrmReceivables::getContractId));
                List<CrmReceivables> groupList =  receivablesMap.get(contractById.getContractId());

                BigDecimal contractSum = new BigDecimal(0.00);
                String contractDealStatus = "未成交";

                for (CrmReceivables crmReceivables : groupList) {
                    if (ObjectUtil.isNotEmpty(crmReceivables.getMoney())) {
                        if(crmReceivables.getCheckStatus() == 1){
                            contractSum = contractSum.add(crmReceivables.getMoney());
                        }
                    }
                }

                if(contractSum.doubleValue() > 0){
                    contractDealStatus = "已成交";
                }

                // 更新合同信息（是否成交，已回款金额，未回款金额）
                contractById.setReceivedMoney(contractSum);
                contractById.setUnreceivedMoney(contractById.getMoney().subtract(contractSum));
                if(contractSum.doubleValue() == contractById.getMoney().doubleValue()){
                    contractById.setRepaymentStatus(CrmRepaidStatusEnum.已还清.getRemarks());
                }else if(contractSum.doubleValue() < contractById.getMoney().doubleValue() && contractSum.doubleValue() > 0){
                    contractById.setRepaymentStatus(CrmRepaidStatusEnum.还款中.getRemarks());
                }
                updateContractDealStatus(contractById,contractDealStatus);

                return;
            }

            if(CrmBusinessConstEnum.账单类别_线下合同.getMsg().equals(contractById.getContractCategory())){
                offlineContractChangeStatus(crmReceivablesList, contractById, customerId, crmContractList, receivables, changeData);
                return;
            }

            String vipDealStatus = "未成交";
            String repaymentStatus = CrmRepaidStatusEnum.还款中.getRemarks();
            Map<Integer, List<CrmReceivables>> receivablesMap = crmReceivablesList.stream().collect(Collectors.groupingBy(CrmReceivables::getContractId));

            String telephone = "";
            for(CrmContract crmContract : crmContractList){
                if (crmContract != null && Integer.valueOf(1).equals(crmContract.getCheckStatus())) {
                    telephone = crmContract.getPhone();
                    String contractDealStatus = "未成交";
                    BigDecimal sum = new BigDecimal(0.00);
                    BigDecimal vipSum = new BigDecimal(0.00);
                    BigDecimal contractSum = new BigDecimal(0.00);
                    List<CrmReceivables> groupList =  receivablesMap.get(crmContract.getContractId());
                    if (CollectionUtil.isNotEmpty(groupList)) {
                        for (CrmReceivables crmReceivables : groupList) {
                            if (ObjectUtil.isNotEmpty(crmReceivables.getMoney())) {
                                sum = sum.add(crmReceivables.getMoney());
                                if(crmReceivables.getCheckStatus() == 1){
                                    contractSum = contractSum.add(crmReceivables.getMoney());
                                    vipSum = vipSum.add(crmReceivables.getMoney());
                                }
                            }
                        }
                        log.info("第二级：回款vipSum"+vipSum);
                    }

                    if(sum.doubleValue() > 0){
                        log.info("第二点五级：sum="+sum);
                        contractDealStatus = "已成交";
                    }
                    if (vipSum.doubleValue() > 0) {
                        log.info("第二点五级：vipSum="+vipSum);
                        vipDealStatus = "已成交";
                    }
                    log.info("第二级：vipDealStatus"+vipDealStatus);
                    //当回款审批通过时更新 合同成交状态
                    if(receivables.getCheckStatus() == 1){
                        log.info("第二级：合同状态：{}，合同Id：{}",contractDealStatus,crmContract.getContractId());
                    }

                    // 更新合同信息（是否成交，已回款金额，未回款金额）
                    crmContract.setReceivedMoney(contractSum);
                    crmContract.setUnreceivedMoney(crmContract.getMoney().subtract(contractSum));
                    if(changeData){
                        if(receivables.getCheckStatus() == 1){
                            crmContract.setRecentBackTime(new Date());
                        }
                    }
                    if(vipSum.doubleValue() == crmContract.getMoney().doubleValue()){
                        repaymentStatus = CrmRepaidStatusEnum.已还清.getRemarks();
                        crmContract.setRepaymentStatus(CrmRepaidStatusEnum.已还清.getRemarks());
                    }else if(vipSum.doubleValue() < crmContract.getMoney().doubleValue() && vipSum.doubleValue() > 0){
                        repaymentStatus = CrmRepaidStatusEnum.还款中.getRemarks();
                        crmContract.setRepaymentStatus(CrmRepaidStatusEnum.还款中.getRemarks());
                    }
                    updateContractDealStatus(crmContract,contractDealStatus);
                }
            }

            String index = CrmEnum.CUSTOMER.getIndex();
            CrmCustomer byId = SpringUtils.getBean(ICrmCustomerService.class).getById(customerId);
            String oldVipDealStatus = byId.getVipDealStatus();
            //更新成交状态  客户不为空 并且未删除
            if (byId != null && byId.getStatus() != 3) {

                //更新 vip成交状态
                if((!vipDealStatus.equals(oldVipDealStatus))){
                    BulkRequest vipBulkRequest = new BulkRequest();
                    byId.setVipDealStatus(vipDealStatus);
                    if("已成交".equals(vipDealStatus)){
//                            byId.setDealTime(new Date());
                        byId.setVipDealTime(new Date());
                        // 设置学员状态为已入学
                        byId.setStudentStatus(Const.ALREADY_ENTRANCE);
                    }else{
//                            byId.setDealTime(null);
                        byId.setVipDealTime(null);
                    }
                    byId.setRepaymentStatus(repaymentStatus);
                    SpringUtils.getBean(ICrmCustomerService.class).updateById(byId);
                    UpdateRequest vipUpdateRequest = new UpdateRequest(index, "_doc", String.valueOf(customerId));
                    Map<String, Object> map = new HashMap<>();
                    map.put("vipDealStatus", vipDealStatus);
                    map.put("repaymentStatus", repaymentStatus);
                    if("已成交".equals(vipDealStatus)){
                        map.put("vipDealTime", DateUtil.formatDateTime(new Date()));
                        map.put("studentStatus",Const.ALREADY_ENTRANCE);
                    }else{
                        map.put("vipDealTime", null);
                        map.put("studentStatus",null);
                    }
                    vipUpdateRequest.doc(map);
                    vipBulkRequest.add(vipUpdateRequest);
                    try {
                        elasticsearchRestTemplate.getClient().bulk(vipBulkRequest, RequestOptions.DEFAULT);
                        elasticsearchRestTemplate.refresh(index);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    //更新线索(表单)模块VIP成交状态.
                    String leadsIndex = CrmEnum.LEADS.getIndex();
                    CrmLeads crmLeads = SpringUtils.getBean(ICrmLeadsService.class).queryLeadsDataBySerialNumber(byId.getSerialNumber());
                    if(BeanUtil.isNotEmpty(crmLeads)){
                        crmLeads.setVipDealStatus(vipDealStatus);
                        if("已成交".equals(vipDealStatus)){
                            crmLeads.setVipDealTime(new Date());
                        }else{
                            crmLeads.setVipDealTime(null);
                        }
                        SpringUtils.getBean(ICrmLeadsService.class).updateById(crmLeads);
                        BulkRequest vipLeadsBulkRequest = new BulkRequest();
                        UpdateRequest vipLeadsUpdateRequest = new UpdateRequest(leadsIndex, "_doc", String.valueOf(crmLeads.getLeadsId()));
                        Map<String, Object> mapLeads = new HashMap<>();
                        mapLeads.put("vipDealStatus", vipDealStatus);
                        if("已成交".equals(vipDealStatus)){
                            mapLeads.put("vipDealTime", DateUtil.formatDateTime(new Date()));
                        }else{
                            mapLeads.put("vipDealTime", null);
                        }
                        vipLeadsUpdateRequest.doc(mapLeads);
                        vipLeadsBulkRequest.add(vipLeadsUpdateRequest);
                        try {
                            elasticsearchRestTemplate.getClient().bulk(vipLeadsBulkRequest, RequestOptions.DEFAULT);
                            elasticsearchRestTemplate.refresh(leadsIndex);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    log.info("回款删除后VIP学员：{}","已成交".equals(vipDealStatus));

                    if("已成交".equals(vipDealStatus)){
                        // 创建VIP学员信息
                        CrmStudent student = new CrmStudent();
                        BeanUtils.copyBeanProp(student,byId);
                        student.setCustomerLabel("正常学员");
                        student.setRiskLabel(CrmBusinessConstEnum.风险提示_正常.getMsg());
                        student.setStudentStatus(Const.ALREADY_ENTRANCE);
                        if(StringUtils.isNotBlank(byId.getAssistantUserId())){
                            student.setAssistantUserId(Long.valueOf(byId.getAssistantUserId()));
                        }
                        if(StringUtils.isBlank(student.getTelephone())){
                            student.setTelephone(telephone);
                        }
                        Integer studentId = crmStudentService.initStudent(student);

                        //转移活动数据
                        List<CrmActivity> crmActivityList = crmActivityService.lambdaQuery().eq(CrmActivity::getActivityType, 2).eq(CrmActivity::getType, 1).eq(CrmActivity::getActivityTypeId, byId.getCustomerId()).list();
                        if (crmActivityList.size() != 0) {
                            crmActivityList.forEach(crmActivity -> {
                                List<FileEntity> leadsRecordFiles = adminFileService.queryFileList(crmActivity.getBatchId());
                                String studentRecordBatchId = IdUtil.simpleUUID();
                                List<String> fileIds = leadsRecordFiles.stream().map(FileEntity::getFileId).collect(Collectors.toList());
                                crmActivity.setBatchId(studentRecordBatchId);
                                crmActivity.setActivityId(null);
                                crmActivity.setActivityType(CrmEnum.STUDENT.getType());
                                crmActivity.setActivityTypeId(studentId);
                                if(CollectionUtil.isNotEmpty(fileIds)){
                                    adminFileService.saveBatchFileEntity(fileIds, studentRecordBatchId);
                                }
                            });
                            crmActivityService.saveBatch(crmActivityList, 100);
                        }

                        //转移操作记录
                        List<Integer> contractIds = crmContractList.stream().map(CrmContract::getContractId).collect(Collectors.toList());
                        List<Integer> receivablesIds = crmReceivablesList.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
                        List<CrmActionRecord> crmActionRecordList = crmActionRecordService.lambdaQuery().eq(CrmActionRecord::getActionId, byId.getCustomerId()).eq(CrmActionRecord::getTypes, 2).list();
//                        List<CrmActionRecord> contractActionRecordList = crmActionRecordService.lambdaQuery().in(CrmActionRecord::getActionId, contractIds).eq(CrmActionRecord::getTypes, 6).list();
//                        List<CrmActionRecord> receivablesActionRecordList = crmActionRecordService.lambdaQuery().in(CrmActionRecord::getActionId, receivablesIds).eq(CrmActionRecord::getTypes, 7).list();
//                        crmActionRecordList.addAll(contractActionRecordList);
//                        crmActionRecordList.addAll(receivablesActionRecordList);
                        crmActionRecordList.forEach(crmActionRecord -> {
                            crmActionRecord.setId(null);
                            if(CrmEnum.CUSTOMER.getType().equals(crmActionRecord.getTypes())){
                                crmActionRecord.setTypes(CrmEnum.STUDENT.getType());
                                crmActionRecord.setActionId(studentId);
                            }
                        });
                        crmActionRecordService.saveBatch(crmActionRecordList, 500);

                        for(CrmContract contract : crmContractList){
                            contract.setStudentId(studentId);
                            crmContractService.updateById(contract);
                            //修改es
                            Map<String, Object> map1 = new HashMap<>();
                            map1.put("studentId", studentId);
                            ElasticUtil.updateField(elasticsearchRestTemplate, map1, contract.getContractId(), CrmEnum.CONTRACT.getIndex());

                            QueryWrapper<CrmReceivables> queryReceivables = new QueryWrapper<>();
                            queryReceivables.eq("contract_id",contract.getContractId());
                            queryReceivables.ne("check_status",7);
                            List<CrmReceivables> list = baseMapper.selectList(queryReceivables);
                            for(CrmReceivables crmReceivables : list){
                                crmReceivables.setStudentId(studentId);
                                updateById(crmReceivables);

                                updateField(map1, Collections.singletonList(crmReceivables.getReceivablesId()));
                            }
                        }
                    }else{
                        String serialNumber = byId.getSerialNumber();
                        log.info("customer.serialNumber:{}",serialNumber);
                        crmStudentService.deleteBySerialNumbers(Collections.singletonList(serialNumber));
                    }

                }else {
                    // 变更学员还款状态
                    BulkRequest customerBulkRequest = new BulkRequest();
                    byId.setRepaymentStatus(repaymentStatus);
                    SpringUtils.getBean(ICrmCustomerService.class).updateById(byId);
                    UpdateRequest customerUpdateRequest = new UpdateRequest(index, "_doc", String.valueOf(customerId));
                    Map<String, Object> map = new HashMap<>();
                    map.put("repaymentStatus", repaymentStatus);
                    customerUpdateRequest.doc(map);
                    customerBulkRequest.add(customerUpdateRequest);
                    try {
                        elasticsearchRestTemplate.getClient().bulk(customerBulkRequest, RequestOptions.DEFAULT);
                        elasticsearchRestTemplate.refresh(index);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                    // 变更VIP学员还款状态
                    CrmStudent student = crmStudentService.queryStudentBySerialNumber(byId.getSerialNumber());
                    if(BeanUtil.isNotEmpty(student)){
                        BulkRequest vipBulkRequest = new BulkRequest();
                        student.setRepaymentStatus(repaymentStatus);
                        SpringUtils.getBean(ICrmStudentService.class).updateById(student);
                        UpdateRequest vipUpdateRequest = new UpdateRequest(CrmEnum.STUDENT.getIndex(), "_doc", String.valueOf(student.getStudentId()));
                        Map<String, Object> vipMap = new HashMap<>();
                        vipMap.put("repaymentStatus", repaymentStatus);
                        vipUpdateRequest.doc(vipMap);
                        vipBulkRequest.add(vipUpdateRequest);
                        try {
                            elasticsearchRestTemplate.getClient().bulk(vipBulkRequest, RequestOptions.DEFAULT);
                            elasticsearchRestTemplate.refresh(CrmEnum.STUDENT.getIndex());
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                }
                if(receivables.getCheckStatus() == 1){
                    //埋点更新合同 现金已回款金额 全额贷已回款金额 分期已回款金额 全额贷代偿金额
                    updateContractMoney(receivables);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public void offlineContractChangeStatus(List<CrmReceivables> crmReceivablesList,CrmContract contractById, Integer customerId, List<CrmContract> crmContractList,CrmReceivables receivables,boolean changeData){
        Map<Integer, List<CrmReceivables>> receivablesMap = crmReceivablesList.stream().collect(Collectors.groupingBy(CrmReceivables::getContractId));
        List<CrmReceivables> groupList =  receivablesMap.get(contractById.getContractId());

        CrmCustomer customer = SpringUtils.getBean(ICrmCustomerService.class).getById(customerId);
        String contractRepaymentStatus = customer.getRepaymentStatus();
        Integer studentStatus = 1;
        BigDecimal contractSum = new BigDecimal("0.00");
        Optional<CrmContract> first = crmContractList.stream().filter(contract -> CrmBusinessConstEnum.账单类别_账单合同.getMsg().equals(contract.getContractCategory()) && CrmBusinessConstEnum.审核状态_已删除.getCode() != contract.getCheckStatus()).findFirst();
        if(CollectionUtil.isEmpty(groupList)){
            // 线下合同下没有回款时,需要恢复还款状态
            if(first.isPresent()){
                CrmContract order = first.get();
                List<CrmReceivables> crmReceivables = receivablesMap.get(order.getContractId());
                Optional<CrmReceivables> optional = crmReceivables.stream().filter(item -> !CrmRepaidStatusEnum.已还清.getRemarks().equals(item.getRepaymentStatus())).min(Comparator.comparing(CrmReceivables::getRepaymentDueDate));
                if (optional.isPresent()) {
                    CrmReceivables rece = optional.get();

                    int result = DateUtils.compareDate(DateUtils.dateTime(rece.getRepaymentDueDate()), DateUtils.getDate());
                    if(result < 0){
                        contractRepaymentStatus = CrmRepaidStatusEnum.已逾期.getRemarks();
                        System.out.println("str1<str2");
                    }else{
                        contractRepaymentStatus = CrmRepaidStatusEnum.还款中.getRemarks();
                    }
                }else{
                    contractRepaymentStatus = CrmRepaidStatusEnum.已还清.getRemarks();
                }
                studentStatus = 1;
            }else {
                contractRepaymentStatus = null;
            }

        }else{
            for (CrmReceivables crmReceivables : groupList) {
                if (ObjectUtil.isNotEmpty(crmReceivables.getMoney())) {
                    if(crmReceivables.getCheckStatus() == 1){
                        contractSum = contractSum.add(crmReceivables.getMoney());
                    }
                }
            }
            if(contractSum.doubleValue() > 0){
                contractRepaymentStatus = CrmRepaidStatusEnum.已退学.getRemarks();
                studentStatus = 0;
            }
        }

        if(StringUtils.isBlank(contractRepaymentStatus) || (!first.isPresent())){
            return;
        }

        String studentStatusToStr = studentStatus == 0 ? CrmBusinessConstEnum.入学状态_已退学.getMsg() : CrmBusinessConstEnum.入学状态_已入学.getMsg();

        // 更新学员
        LambdaUpdateWrapper<CrmCustomer> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(CrmCustomer::getRepaymentStatus, contractRepaymentStatus);
        wrapper.set(CrmCustomer::getStudentStatus, studentStatus);
        wrapper.eq(CrmCustomer::getCustomerId,customerId);
        SpringUtils.getBean(ICrmCustomerService.class).update(wrapper);

        // 更新账单合同
        CrmContract order = first.get();
        LambdaUpdateWrapper<CrmContract> contractWrapper = new LambdaUpdateWrapper<>();
        contractWrapper.set(CrmContract::getRepaymentStatus, contractRepaymentStatus);
        contractWrapper.set(CrmContract::getStudentStatus, studentStatusToStr);
        contractWrapper.eq(CrmContract::getContractId,order.getContractId());
        if(CrmRepaidStatusEnum.已退学.getRemarks().equals(contractRepaymentStatus)){
            contractWrapper.set(CrmContract::getDropOutTime, new Date());
        }else{
            contractWrapper.set(CrmContract::getDropOutTime, null);
        }
        SpringUtils.getBean(ICrmContractService.class).update(contractWrapper);

        // 更新线下合同
        LambdaUpdateWrapper<CrmContract> offlineContractWrapper = new LambdaUpdateWrapper<>();
        if(contractSum.compareTo(contractById.getMoney()) >= 0){
            offlineContractWrapper.set(CrmContract::getRepaymentStatus, CrmRepaidStatusEnum.已还清.getRemarks());
        }else{
            offlineContractWrapper.set(CrmContract::getRepaymentStatus, CrmRepaidStatusEnum.还款中.getRemarks());
        }
        offlineContractWrapper.set(CrmContract::getStudentStatus, studentStatusToStr);
        if(CrmRepaidStatusEnum.已退学.getRemarks().equals(contractRepaymentStatus)){
            offlineContractWrapper.set(CrmContract::getDropOutTime, new Date());
        }else{
            offlineContractWrapper.set(CrmContract::getDropOutTime, null);
        }
        if(changeData){
            if(receivables.getCheckStatus() == 1){
                offlineContractWrapper.set(CrmContract::getRecentBackTime, new Date());
            }
        }
        offlineContractWrapper.set(CrmContract::getReceivedMoney,contractSum);
        offlineContractWrapper.set(CrmContract::getUnreceivedMoney,contractById.getMoney().subtract(contractSum));
        offlineContractWrapper.eq(CrmContract::getContractId,contractById.getContractId());
        SpringUtils.getBean(ICrmContractService.class).update(offlineContractWrapper);

        // 更新首付款合同
        List<CrmContract> contractList = crmContractList.stream().filter(item -> CrmBusinessConstEnum.账单类别_首付款合同.getMsg().equals(item.getContractCategory()) && CrmBusinessConstEnum.审核状态_已删除.getCode() != item.getCheckStatus()).collect(Collectors.toList());
        if(!CollectionUtil.isEmpty(contractList)){
            CrmContract contract = contractList.get(0);
            LambdaUpdateWrapper<CrmContract> sfkContractWrapper = new LambdaUpdateWrapper<>();
            sfkContractWrapper.set(CrmContract::getStudentStatus, studentStatusToStr);
            if(CrmRepaidStatusEnum.已退学.getRemarks().equals(contractRepaymentStatus)){
                offlineContractWrapper.set(CrmContract::getDropOutTime, new Date());
            }else{
                offlineContractWrapper.set(CrmContract::getDropOutTime, null);
            }
            sfkContractWrapper.eq(CrmContract::getContractId,contract.getContractId());
            SpringUtils.getBean(ICrmContractService.class).update(sfkContractWrapper);
        }

        // 更新账单合同未还回款的还款状态
        List<Integer> allReceivablesIds = crmReceivablesList.stream().map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
        List<CrmReceivables> crmReceivables = receivablesMap.get(order.getContractId());
        List<Integer> receivablesIds = crmReceivables.stream().filter(receivables1 -> !CrmRepaidStatusEnum.已还清.getRemarks().equals(receivables1.getRepaymentStatus()) && CrmBusinessConstEnum.审核状态_已删除.getCode() != receivables1.getCheckStatus()).map(CrmReceivables::getReceivablesId).collect(Collectors.toList());
        if(!CollectionUtil.isEmpty(receivablesIds)){
            UpdateWrapper<CrmReceivables> receivablesUpdateWrapper = new UpdateWrapper<>();
            receivablesUpdateWrapper.set("repayment_status", contractRepaymentStatus);
            receivablesUpdateWrapper.in("receivables_id", receivablesIds);
            update(receivablesUpdateWrapper);
        }
        // 更新该学员下所有回款入学状态
        UpdateWrapper<CrmReceivables> allReceivablesWrapper = new UpdateWrapper<>();
        allReceivablesWrapper.set("student_status", studentStatusToStr);
        allReceivablesWrapper.in("receivables_id", allReceivablesIds);
        update(allReceivablesWrapper);

        // 更新VIP学员
        CrmStudent student = SpringUtils.getBean(ICrmStudentService.class).queryStudentBySerialNumber(customer.getSerialNumber());
        if(ObjectUtils.isNotEmpty(student)){
            LambdaUpdateWrapper<CrmStudent> studentWrapper = new LambdaUpdateWrapper<>();
            studentWrapper.set(CrmStudent::getRepaymentStatus, contractRepaymentStatus);
            studentWrapper.set(CrmStudent::getStudentStatus, studentStatus);
            studentWrapper.eq(CrmStudent::getStudentId,student.getStudentId());
            SpringUtils.getBean(ICrmStudentService.class).update(studentWrapper);
        }

        //查询客户下所有退款
        QueryWrapper<CrmRefund> crmRefundQueryWrapper = new QueryWrapper<>();
        crmRefundQueryWrapper.eq("customer_id",customerId);
        crmRefundQueryWrapper.eq("contract_id",contractById.getContractId());
        crmRefundQueryWrapper.ne("check_status", 7);
        List<CrmRefund> crmRefundList = crmReFundService.list(crmRefundQueryWrapper);

        if(!CollectionUtil.isEmpty(crmRefundList)){
            List<Integer> refundIds = crmRefundList.stream().map(CrmRefund::getRefundId).collect(Collectors.toList());

            LambdaUpdateWrapper<CrmRefund> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.set(CrmRefund::getCheckStatus,7);
            updateWrapper.eq(CrmRefund::getCustomerId,customerId);
            updateWrapper.eq(CrmRefund::getContractId,contractById.getContractId());
            updateWrapper.ne(CrmRefund::getCheckStatus, 7);
            crmReFundService.update(updateWrapper);

            DeleteQuery query = new DeleteQuery();
            query.setQuery(QueryBuilders.idsQuery().addIds(refundIds.stream().map(Object::toString).toArray(String[]::new)));
            query.setIndex(CrmEnum.REFUND.getIndex());
            query.setType(getDocType());
            getRestTemplate().delete(query);
        }
        // 线下合同审核通过生成退款
        CrmRefund refund = null;
        if(contractSum.doubleValue() > 0){

            refund = new CrmRefund();

            // 退款编号
            List<AdminConfigBo> configList = adminService.queryConfigByName("numberSetting");
            AdminConfigBo adminConfig = configList.stream().filter(config -> Objects.equals(CrmEnum.REFUND.getType().toString(), config.getValue())).collect(Collectors.toList()).get(0);
            if (adminConfig.getStatus() == 1 && StrUtil.isEmpty(refund.getNumber())) {
                String result = crmNumberSettingService.generateNumber(adminConfig, null);
                if(BeanUtil.isEmpty(refund.getNumber())){
                    refund.setNumber(result);
                }
            }

            refund.setCustomerId(customerId);
            refund.setContractId(contractById.getContractId());
            refund.setContractMoney(contractById.getMoney());
            refund.setStudentId(contractById.getStudentId());
            if(ObjectUtils.isNotEmpty(student)){
                refund.setVipPeriods(student.getVipPeriods());
            }
            refund.setSource(contractById.getSource());
            refund.setCourseSource(contractById.getCourseSource());
            refund.setTeacherId(contractById.getTeacherId());
            refund.setOwnerUserId(contractById.getOwnerUserId());
            refund.setCreateUserId(contractById.getCreateUserId());
            refund.setRefundUserId(contractById.getCreateUserId());
            if(refund.getOwnerUserId() != null){
                //设置负责人所在部门
                refund.setOwnerDeptId(String.valueOf(UserCacheUtil.getUserInfo(refund.getOwnerUserId()).getDeptId()));
            }
            refund.setCreateTime(DateUtils.getNowDate());
            refund.setUpdateTime(DateUtils.getNowDate());
            refund.setRefundDate(new Date());
            refund.setReturnTime(order.getPaymentTime());
            refund.setMoney(new BigDecimal(0));
            refund.setBillMoney(contractSum);
            refund.setReturnType(contractById.getReturnType());
            refund.setCheckStatus(CrmBusinessConstEnum.审核状态_通过.getCode());
            refund.setRefundCategory(CrmBusinessConstEnum.退款状态_账单退款.getMsg());
            refund.setContractCategory(CrmBusinessConstEnum.账单类别_线下合同.getMsg());
            crmReFundService.save(refund);
        }

        //更新客户ES
        BulkRequest bulkRequest = new BulkRequest();
        UpdateRequest updateRequest = new UpdateRequest(CrmEnum.CUSTOMER.getIndex(), "_doc", String.valueOf(customerId));
        Map<String, Object> map = new HashMap<>();
        map.put("repaymentStatus",contractRepaymentStatus);
        map.put("studentStatus",studentStatus);
        updateRequest.doc(map);
        bulkRequest.add(updateRequest);
        try {
            elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
            elasticsearchRestTemplate.refresh(CrmEnum.CUSTOMER.getIndex());
        } catch (IOException e) {
            e.printStackTrace();
        }

        //更新账单合同ES
        BulkRequest contractBulkRequest = new BulkRequest();
        UpdateRequest contractUpdateRequest = new UpdateRequest(CrmEnum.CONTRACT.getIndex(), "_doc", String.valueOf(order.getContractId()));
        Map<String, Object> contractMap = new HashMap<>();
        contractMap.put("repaymentStatus",contractRepaymentStatus);
        contractMap.put("studentStatus", studentStatusToStr);
        if(CrmRepaidStatusEnum.已退学.getRemarks().equals(contractRepaymentStatus)){
            contractMap.put("dropOutTime",DateUtils.getTime());
        }else{
            contractMap.put("dropOutTime", null);
        }
        contractUpdateRequest.doc(contractMap);
        contractBulkRequest.add(contractUpdateRequest);
        try {
            elasticsearchRestTemplate.getClient().bulk(contractBulkRequest, RequestOptions.DEFAULT);
            elasticsearchRestTemplate.refresh(CrmEnum.CONTRACT.getIndex());
        } catch (IOException e) {
            e.printStackTrace();
        }

        //更新线下合同ES
        BulkRequest offlineContractBulkRequest = new BulkRequest();
        UpdateRequest offlineContractUpdateRequest = new UpdateRequest(CrmEnum.CONTRACT.getIndex(), "_doc", String.valueOf(contractById.getContractId()));
        Map<String, Object> offlineContractMap = new HashMap<>();
        if(contractSum.compareTo(contractById.getMoney()) >= 0){
            offlineContractMap.put("repaymentStatus",CrmRepaidStatusEnum.已还清.getRemarks());
        }else{
            offlineContractMap.put("repaymentStatus",CrmRepaidStatusEnum.还款中.getRemarks());
        }
        offlineContractMap.put("studentStatus", studentStatusToStr);
        if(CrmRepaidStatusEnum.已退学.getRemarks().equals(contractRepaymentStatus)){
            offlineContractMap.put("dropOutTime",DateUtils.getTime());
        }else{
            offlineContractMap.put("dropOutTime", null);
        }
        offlineContractMap.put("receivedMoney",contractSum);
        offlineContractMap.put("unreceivedMoney",contractById.getMoney().subtract(contractSum));
        if(changeData){
            if(receivables.getCheckStatus() == 1){
                offlineContractMap.put("recentBackTime", DateUtils.getTime());
            }
        }
        offlineContractUpdateRequest.doc(offlineContractMap);
        offlineContractBulkRequest.add(offlineContractUpdateRequest);
        try {
            elasticsearchRestTemplate.getClient().bulk(offlineContractBulkRequest, RequestOptions.DEFAULT);
            elasticsearchRestTemplate.refresh(CrmEnum.CONTRACT.getIndex());
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 更新首付款合同ES
        if(!CollectionUtil.isEmpty(contractList)){
            CrmContract contract = contractList.get(0);
            BulkRequest sfkContractBulkRequest = new BulkRequest();
            UpdateRequest sfkContractUpdateRequest = new UpdateRequest(CrmEnum.CONTRACT.getIndex(), "_doc", String.valueOf(contract.getContractId()));
            Map<String, Object> sfkContractMap = new HashMap<>();
            sfkContractMap.put("studentStatus", studentStatusToStr);
            if(CrmRepaidStatusEnum.已退学.getRemarks().equals(contractRepaymentStatus)){
                sfkContractMap.put("dropOutTime",DateUtils.getTime());
            }else{
                sfkContractMap.put("dropOutTime", null);
            }
            sfkContractUpdateRequest.doc(sfkContractMap);
            sfkContractBulkRequest.add(sfkContractUpdateRequest);
            try {
                elasticsearchRestTemplate.getClient().bulk(sfkContractBulkRequest, RequestOptions.DEFAULT);
                elasticsearchRestTemplate.refresh(CrmEnum.CONTRACT.getIndex());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if(contractSum.doubleValue() > 0){
            CrmModelSaveBO refundModel = new CrmModelSaveBO();
            refundModel.setEntity(BeanUtil.beanToMap(refund));
            refundModel.getEntity().put("contractNum", contractById.getNum());
            refundModel.getEntity().put("contractMoney", contractById.getMoney());
            refundModel.getEntity().put("ownerUserId", contractById.getOwnerUserId());
            refundModel.getEntity().put("ownerDeptId", refund.getOwnerDeptId());
            if(refund.getOwnerDeptId() != null){
                String deptName = this.adminService.queryDeptName(Integer.valueOf(String.valueOf(refund.getOwnerDeptId())));
                refundModel.getEntity().put("ownerDeptName", deptName);
            }
            refundModel.getEntity().put("teacherId", refund.getTeacherId());
            if(refund.getTeacherId() != null){
                refundModel.getEntity().put("teacherName", adminService.queryUserName(refund.getTeacherId()));
            }
            if(refund.getOwnerUserId() != null){
                refundModel.getEntity().put("ownerUserName", adminService.queryUserName(refund.getOwnerUserId()));
            }
            if(refund.getRefundUserId() != null){
                refundModel.getEntity().put("refundUserName", adminService.queryUserName(refund.getRefundUserId()));
            }
            if(ObjectUtil.isNotEmpty(student)){
                refundModel.getEntity().put("studentName", student.getCustomerName());
            }
            savePageByLable(refundModel, refund.getRefundId(), false, CrmEnum.REFUND.getType());
        }

        // 更新回款ES 分别更新还款状态及入学状态
        if(!CollectionUtil.isEmpty(receivablesIds)){
            ElasticUtil.updateField(elasticsearchRestTemplate,"repaymentStatus",contractRepaymentStatus,receivablesIds, CrmEnum.RECEIVABLES.getIndex());
        }
        ElasticUtil.updateField(elasticsearchRestTemplate,"studentStatus", studentStatusToStr,allReceivablesIds, CrmEnum.RECEIVABLES.getIndex());

        if(ObjectUtils.isNotEmpty(student)){
            //更新VIP学员ES
            BulkRequest studentBulkRequest = new BulkRequest();
            UpdateRequest studentUpdateRequest = new UpdateRequest(CrmEnum.STUDENT.getIndex(), "_doc", String.valueOf(student.getStudentId()));
            Map<String, Object> studentMap = new HashMap<>();
            studentMap.put("repaymentStatus",contractRepaymentStatus);
            studentMap.put("studentStatus",studentStatus);
            studentUpdateRequest.doc(studentMap);
            studentBulkRequest.add(studentUpdateRequest);
            try {
                elasticsearchRestTemplate.getClient().bulk(studentBulkRequest, RequestOptions.DEFAULT);
                elasticsearchRestTemplate.refresh(CrmEnum.STUDENT.getIndex());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if(contractSum.doubleValue() > 0){
            if(student.getAssistantUserId() != null){
                // 账单合同退学新增消息
                AdminMessage adminMessage = new AdminMessage();
                adminMessage.setTitle(student.getCustomerName());
                adminMessage.setContent(contractById.getNum());
                adminMessage.setTypeId(student.getStudentId());
                adminMessage.setCreateUser(0L);
                adminMessage.setRecipientUser(student.getAssistantUserId());
                adminMessage.setLabel(6);
                adminMessage.setType(AdminMessageEnum.CRM_CONTRACT_DROPOUT.getType());
                adminMessage.setIsRead(0);
                adminMessageService.saveOrUpdateMessage(adminMessage);
            }
        }
    }


    //埋点更新合同 现金已回款金额 全额贷已回款金额 分期已回款金额 全额贷代偿金额
    public void updateContractMoney(CrmReceivables receivables){

        CrmReceivables queryRe =  baseMapper.selectById(receivables.getReceivablesId());
        //更新合同 现金已回款金额 全额贷已回款金额 分期已回款金额 全额贷代偿金额
        CrmContract contract = crmContractService.queryContractById(queryRe.getContractId());

        QueryWrapper<CrmReceivables> queryReceivables = new QueryWrapper<>();
        queryReceivables.eq("contract_id",contract.getContractId());
        queryReceivables.eq("check_status",1);
        List<CrmReceivables> list = baseMapper.selectList(queryReceivables);
        BigDecimal money = new BigDecimal(0.00);
        for(CrmReceivables crmReceivables : list){
            money = money.add(crmReceivables.getMoney());
        }
        boolean b = false;
        Map<String, Object> map = new HashMap<>();
        CrmContract upContract = new CrmContract();
        upContract.setContractId(contract.getContractId());
        if(StringUtils.isNotBlank(contract.getReturnType()) && contract.getReturnType().startsWith("现金")){
            b=true;
        }else if(StringUtils.isNotBlank(contract.getReturnType()) && contract.getReturnType().startsWith("全额贷款")){
            //全额贷款 并且 是手动创建的 非裂变的才会进入埋点
            b=true;
        }else if(StringUtils.isNotBlank(contract.getReturnType()) && contract.getReturnType().startsWith("账单分期")){
            b=true;
        }

        if(b){
            //更新合同金额
            String index = CrmEnum.CONTRACT.getIndex();
            SpringUtils.getBean(ICrmContractService.class).updateById(upContract);
            BulkRequest bulkRequest = new BulkRequest();
            UpdateRequest updateRequest = new UpdateRequest(index, "_doc", String.valueOf(contract.getContractId()));


            updateRequest.doc(map);
            bulkRequest.add(updateRequest);
            try {
                elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
                elasticsearchRestTemplate.refresh(index);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void updateContractReturnType(CrmContract contract){
        //更新合同付款方式
        String index = CrmEnum.CONTRACT.getIndex();
        SpringUtils.getBean(ICrmContractService.class).updateById(contract);
        BulkRequest bulkRequest = new BulkRequest();
        UpdateRequest updateRequest = new UpdateRequest(index, "_doc", String.valueOf(contract.getContractId()));
        Map<String, Object> map = new HashMap<>();
        map.put("returnType",contract.getReturnType());
        updateRequest.doc(map);
        bulkRequest.add(updateRequest);
        try {
            elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
            elasticsearchRestTemplate.refresh(index);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }




    /**
     * 更新合同 成交状态
     * @param contract
     * @param dealStatus
     */
    public void updateContractDealStatus(CrmContract contract, String dealStatus){

        String index = CrmEnum.CONTRACT.getIndex();
        String oldDealStatus = contract.getDealStatus();
        if(!dealStatus.equals(oldDealStatus)){
            contract.setDealStatus(dealStatus);
            if("已成交".equals(dealStatus)){
                contract.setDealTime(new Date());
            }else{
                contract.setDealTime(null);
            }
            SpringUtils.getBean(ICrmContractService.class).updateById(contract);
            BulkRequest bulkRequest = new BulkRequest();
            UpdateRequest updateRequest = new UpdateRequest(index, "_doc", String.valueOf(contract.getContractId()));
            Map<String, Object> map = new HashMap<>();
            map.put("dealStatus", dealStatus);
            if("已成交".equals(dealStatus)){
                map.put("dealTime", DateUtil.formatDateTime(new Date()));
            }else{
                map.put("dealTime", null);
            }
            map.put("repaymentStatus",contract.getRepaymentStatus());
            map.put("receivedMoney",contract.getReceivedMoney());
            map.put("unreceivedMoney",contract.getUnreceivedMoney());
            map.put("recentBackTime",DateUtil.formatDateTime(contract.getRecentBackTime()));
            updateRequest.doc(map);
            bulkRequest.add(updateRequest);
            try {
                elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
                elasticsearchRestTemplate.refresh(index);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else{
            //更新合同金额
            SpringUtils.getBean(ICrmContractService.class).updateById(contract);
            BulkRequest bulkRequest = new BulkRequest();
            UpdateRequest updateRequest = new UpdateRequest(index, "_doc", String.valueOf(contract.getContractId()));
            Map<String, Object> map = new HashMap<>();
            map.put("repaymentStatus",contract.getRepaymentStatus());
            map.put("receivedMoney",contract.getReceivedMoney());
            map.put("unreceivedMoney",contract.getUnreceivedMoney());
            map.put("recentBackTime",DateUtil.formatDateTime(contract.getRecentBackTime()));
            updateRequest.doc(map);
            bulkRequest.add(updateRequest);
            try {
                elasticsearchRestTemplate.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
                elasticsearchRestTemplate.refresh(index);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 删除回款改变合同状态 - 删除调用
     * @param receivables
     */
    public void changeCustomerStatus(CrmReceivables receivables){
        CrmContract contract = crmContractService.getById(receivables.getContractId());
        if(BeanUtil.isNotEmpty(contract)){
            BigDecimal contractMoney = baseMapper.querySumMoneyByContractId(contract.getContractId()).subtract(receivables.getMoney());
            if(contractMoney.doubleValue() < 500){
                LambdaUpdateWrapper<CrmContract> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(CrmContract::getDealStatus, "未成交");
                updateWrapper.set(CrmContract::getDealTime, null);
                updateWrapper.set(CrmContract::getReceivedMoney, contractMoney.subtract(receivables.getMoney()));
                updateWrapper.set(CrmContract::getUnreceivedMoney, contractMoney.add(receivables.getMoney()));
                updateWrapper.eq(CrmContract::getContractId, contract.getContractId());
                crmContractService.update(updateWrapper);
                CrmContract newContract = crmContractService.getById(contract.getContractId());
                Map<String, Object> map = new HashMap<>();
                map.put("dealStatus", newContract.getDealStatus());
                map.put("dealTime", newContract.getDealTime());
                map.put("receivedMoney", newContract.getReceivedMoney());
                map.put("unreceivedMoney", newContract.getUnreceivedMoney());
                ElasticUtil.updateField(elasticsearchRestTemplate, map, newContract.getContractId(), CrmEnum.CONTRACT.getIndex());
            }else{
                LambdaUpdateWrapper<CrmContract> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(CrmContract::getDealStatus, "已成交");
                updateWrapper.set(CrmContract::getDealTime, new Date());
                updateWrapper.eq(CrmContract::getContractId, contract.getContractId());
                crmContractService.update(updateWrapper);
                CrmContract newContract = crmContractService.getById(contract.getContractId());
                Map<String, Object> map = new HashMap<>();
                map.put("dealStatus", newContract.getDealStatus());
                map.put("dealTime", DateFormatUtils.format(newContract.getDealTime(),"yyyy-MM-dd HH:mm:ss"));
                ElasticUtil.updateField(elasticsearchRestTemplate, map, newContract.getContractId(), CrmEnum.CONTRACT.getIndex());
            }
        }
    }

    /**
     * 根据客户Id查询客户下回款信息总数（审批中及审批通过）
     * @param customerId
     * @return
     */
    @Override
    public Integer queryCountReceivablesByCustomerId(Integer customerId){
        return this.baseMapper.queryCountReceivablesByCustomerId(customerId);
    }
    /**
     * 根据vip学员Id查询客户下回款信息总数（审批中及审批通过）
     * @param studentId
     * @return
     */
    @Override
    public Integer queryCountReceivablesByStudentId(Integer studentId){
        return this.baseMapper.queryCountReceivablesByStudentId(studentId);
    }

    @Override
    public List<JSONObject> queryReceivablesByThreeOrderNo(String threePartOrderNo){
        return this.baseMapper.queryReceivablesByThreeOrderNo(threePartOrderNo);
    }

    @Override
    public List<JSONObject> queryReceivablesByThreeOrderNoByChect(String threePartOrderNo){
        return this.baseMapper.queryReceivablesByThreeOrderNoByChect(threePartOrderNo);
    }

    @Override
    public List<JSONObject> queryReceivablesByStudentCell(String studentCell){
        return this.baseMapper.queryReceivablesByStudentCell(studentCell);
    }

    public List<String> queryOverdueStatus(){
        List<CrmModelFiledVO> filedList = crmFieldService.queryField(getLabel().getType());
        String options = "";
        for(CrmModelFiledVO modelFiledVO : filedList){
            if("overdueStatus".equals(modelFiledVO.getFieldName())){
                options = modelFiledVO.getOptions();
            }
        }
        return Arrays.asList(options.split(","));
    }

    @Override
    public void checkStatus(Integer id) {
        UserInfo userinfo = UserUtil.getUser();
        CrmReceivables receivables = getById(id);
        if(!Optional.ofNullable(receivables).isPresent() || !receivables.getCreateUserId().equals(userinfo.getUserId())){
            throw new CrmException(CrmCodeEnum.CRM_NO_AUTH);
        }

        if (receivables.getCheckStatus() == 1){
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_PLAN_EXAMINE_PASS_ERROR);
        }

        LambdaUpdateWrapper<CrmReceivables> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(CrmReceivables::getReceivablesId, id);
        wrapper.set(CrmReceivables::getCheckStatus, 1);
        update(wrapper);

        Map<String, Object> map = new HashMap<>();
        map.put("checkStatus", 1);
        ElasticUtil.updateField(elasticsearchRestTemplate, map, id, CrmEnum.RECEIVABLES.getIndex());

    }

    /**
     * 下载导入模板
     *
     * @param response resp
     * @throws IOException ex
     */
    @Override
    public void downloadExcel(HttpServletResponse response) throws IOException {
        List<CrmModelFiledVO> crmModelFiledList = queryExportField(null);
        crmModelFiledList.removeIf(model -> Arrays.asList(FieldEnum.FILE, FieldEnum.CHECKBOX, FieldEnum.USER, FieldEnum.STRUCTURE).contains(FieldEnum.parse(model.getType())));
        HSSFWorkbook wb = new HSSFWorkbook();
        HSSFSheet sheet = wb.createSheet("账单分期回款");
        sheet.setDefaultRowHeight((short) 400);
        CellStyle textStyle = wb.createCellStyle();
        DataFormat format = wb.createDataFormat();
        textStyle.setDataFormat(format.getFormat("@"));
        for (int i = 0; i < crmModelFiledList.size() + 2; i++) {
            if (crmModelFiledList.size() > i && Objects.equals(crmModelFiledList.get(i).getType(), FieldEnum.DATE.getType())) {
                if(crmModelFiledList.get(i).getFieldName().equals("returnTime")){
                    sheet.setDefaultColumnStyle(i, textStyle);
                }else{
                    CellStyle dateStyle = wb.createCellStyle();
                    DataFormat dateFormat = wb.createDataFormat();
                    dateStyle.setDataFormat(dateFormat.getFormat(DatePattern.NORM_DATE_PATTERN));
                    sheet.setDefaultColumnStyle(i, dateStyle);
                }
            } else if (crmModelFiledList.size() > i && Objects.equals(crmModelFiledList.get(i).getType(), FieldEnum.DATETIME.getType())) {
                CellStyle dateStyle = wb.createCellStyle();
                DataFormat dateFormat = wb.createDataFormat();
                dateStyle.setDataFormat(dateFormat.getFormat(DatePattern.NORM_DATETIME_PATTERN));
                sheet.setDefaultColumnStyle(i, dateStyle);
            } else {
                sheet.setDefaultColumnStyle(i, textStyle);
            }
            sheet.setColumnWidth(i, 20 * 256);
        }
        HSSFRow titleRow = sheet.createRow(0);
        CellStyle cellStyle = wb.createCellStyle();
        cellStyle.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        Font font = wb.createFont();
        font.setBold(true);
        font.setFontHeightInPoints((short) 16);
        cellStyle.setFont(font);
        titleRow.createCell(0).setCellValue("账单分期回款导入模板(*)为必填项");
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        titleRow.getCell(0).setCellStyle(cellStyle);
        CellRangeAddress region = new CellRangeAddress(0, 0, 0, crmModelFiledList.size() + 1);
        sheet.addMergedRegion(region);
        try {
            HSSFRow row = sheet.createRow(1);
            for (int i = 0; i < crmModelFiledList.size(); i++) {
                CrmModelFiledVO record = crmModelFiledList.get(i);
                String fieldName = "_" + record.getFieldName();
                fieldName = fieldName.replaceAll("[\\n`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。， 、？]", "");

                HSSFCell cell = row.createCell(i);
                String cellValue = record.getName() + (record.getIsNull() == 1 ? "(*)" : "");
                if(FieldEnum.LEVEL_LINKAGE.getType().equals(record.getType())){
                    cellValue = cellValue + "(每级之间请用“|”分割)";
                }
                cell.setCellValue(cellValue);
                List<String> setting = record.getSetting().stream().map(Object::toString).collect(Collectors.toList());
                if (setting != null && setting.size() != 0) {
                    HSSFSheet hidden = wb.createSheet(fieldName);
                    HSSFCell sheetCell = null;
                    for (int j = 0, length = setting.size(); j < length; j++) {
                        String name = setting.get(j);
                        HSSFRow sheetRow = hidden.createRow(j);
                        sheetCell = sheetRow.createCell(0);
                        sheetCell.setCellValue(name);
                    }
                    Name namedCell = wb.createName();
                    namedCell.setNameName(fieldName);
                    namedCell.setRefersToFormula(fieldName + "!$A$1:$A$" + setting.size());
                    CellRangeAddressList regions = new CellRangeAddressList(2, Integer.MAX_VALUE, i, i);
                    DVConstraint constraint = DVConstraint.createFormulaListConstraint(fieldName);
                    HSSFDataValidation dataValidation = new HSSFDataValidation(regions, constraint);
                    wb.setSheetHidden(wb.getSheetIndex(hidden), true);
                    sheet.addValidationData(dataValidation);
                }
            }
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
            response.setHeader("Content-Disposition", "attachment;filename=bill_receivables_import.xls");
            wb.write(response.getOutputStream());
        } catch (Exception e) {
            log.error("error", e);
        } finally {
            wb.close();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importBillData(CrmContractSaveBO crmModel) {

        if(Optional.ofNullable(crmModel.getEntity().get("returnTime")).isPresent()){
            String str = String.valueOf(crmModel.getEntity().get("returnTime"));
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            try {
                Date d = (Date) format.parseObject(str);
                String formatStr = format.format(d);
                if(!str.equals(formatStr)){
                    throw new CrmException(CrmCodeEnum.CRM_DATE_FORMAT_ERROR);
                }
            } catch (ParseException e) {
                throw new CrmException(CrmCodeEnum.CRM_DATE_FORMAT_ERROR);
            }
        }

        if(Optional.ofNullable(crmModel.getEntity().get("money")).isPresent()){
            try {
                BigDecimal money = new BigDecimal(String.valueOf(crmModel.getEntity().get("money")));
                if(new BigDecimal(0.00).compareTo(money) >= 0){
                    throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_ZERO);
                }
            } catch (Exception e) {
                throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_MONEY_ZERO);
            }
        }
       String contractNum =  String.valueOf(crmModel.getEntity().get("contractNum"));

        CrmReceivables crmReceivables = BeanUtil.copyProperties(crmModel.getEntity(), CrmReceivables.class);

        CrmContract crmContract = crmContractService.queryContractByNum(contractNum);
        if (crmContract == null || !crmContract.getCheckStatus().equals(1)) {
            throw new CrmException(CrmCodeEnum.CRM_RECEIVABLES_ADD_ERROR);
        }

        if (!crmContract.getReturnType().startsWith("账单分期")) {
            throw new CrmException(CrmCodeEnum.CRM_BILL_RECEIVABLES_RETURN_TYPE_ERROR);
        }

        JSONObject queryFirstReceivables = getBaseMapper().queryFirstReceivablesByContractId(crmContract.getContractId());
        if(!Optional.ofNullable(queryFirstReceivables).isPresent()){
            throw new CrmException(CrmCodeEnum.CRM_NO_BILL_RECEIVABLES_DATA_ERROR);
        }

        CrmReceivables queryRe =  baseMapper.selectById(queryFirstReceivables.getInteger("receivablesId"));

        CrmReceivables newReceivables = new CrmReceivables();
        BeanUtil.copyProperties(queryRe,newReceivables);
        newReceivables.setReceivablesId(null);
        List<AdminConfigBo> configList = adminService.queryConfigByName("numberSetting");
        AdminConfigBo adminConfig = configList.stream().filter(config -> Objects.equals(getLabel().getType().toString(), config.getValue())).collect(Collectors.toList()).get(0);
        String result = crmNumberSettingService.generateNumber(adminConfig, null);
        newReceivables.setNumber(result);
        String batchId =  IdUtil.simpleUUID();
        newReceivables.setBatchId(batchId);
        newReceivables.setMoney(crmReceivables.getMoney());
        newReceivables.setCreateTime(new Date());
        newReceivables.setUpdateTime(new Date());
        baseMapper.insert(newReceivables);

        CrmContractSaveBO saveCrmModel = new CrmContractSaveBO();
        saveCrmModel.setEntity(BeanUtil.beanToMap(newReceivables));

        LambdaQueryWrapper<CrmReceivablesData> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CrmReceivablesData::getBatchId, queryRe.getBatchId());
        List<CrmReceivablesData> dataList = crmReceivablesDataService.list(wrapper);
        List<CrmModelFiledVO> field = new ArrayList<>();
        for(CrmReceivablesData data : dataList){
            data.setBatchId(batchId);
            data.setId(null);
            data.setCreateTime(new Date());
            crmReceivablesDataService.save(data);
            CrmModelFiledVO vo = new CrmModelFiledVO();
            vo.setFieldName(data.getName());
            vo.setValue(data.getValue());
            field.add(vo);
        }
        saveCrmModel.setField(field);
        savePage(saveCrmModel, newReceivables.getReceivablesId(),false);

        LambdaQueryWrapper<CrmReceivables> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(CrmReceivables::getNumber,result);
        CrmReceivables receivables = getBaseMapper().selectOne(queryWrapper);


        if ((receivables.getCheckStatus() == 1 || receivables.getCheckStatus() == 3)) {

            //更新合同中已回款金额
            updateCustomerDeal(receivables,true);
//                examineRecordService.updateContractMoney(crmReceivables.getReceivablesId());


        }
    }


    public List<Map<String,Object>> queryPutinStatis(List<Integer> customerIds,List<Long> userIdList){
        return baseMapper.queryPutinStatis(customerIds,userIdList);
    }

    public List<Map<String,Object>> queryAllPutinStatis(List<Integer> customerIds,List<Long> userIdList){
        return baseMapper.queryAllPutinStatis(customerIds,userIdList);
    }

    public List<CrmRoiStatisVO> queryRoiStatis(String startDate, String endDate){
        return baseMapper.queryRoiStatis(startDate, endDate);
    }

    public List<CrmRoiStatisVO> queryExpectRoiStatis(String startDate, String endDate){
        return baseMapper.queryExpectRoiStatis(startDate, endDate);
    }

    public BigDecimal queryReceivablesMoneyByData(CrmRoiPutinPageBO crmRoiPutinPageBO){
        return baseMapper.queryReceivablesMoneyByData(crmRoiPutinPageBO);
    }

    public BigDecimal queryExpectReceivablesMoneyByData(CrmRoiPutinPageBO crmRoiPutinPageBO){
        return baseMapper.queryExpectReceivablesMoneyByData(crmRoiPutinPageBO);
    }

    public List<CrmRoiStatisVO> queryPutinStatisByFormDate(CrmRoiPutinPageBO crmRoiPutinPageBO){
        return baseMapper.queryPutinStatisByFormDate(crmRoiPutinPageBO);
    }

    public List<CrmRoiStatisVO> queryExpectPutinStatisByFormDate(CrmRoiPutinPageBO crmRoiPutinPageBO){
        return baseMapper.queryExpectPutinStatisByFormDate(crmRoiPutinPageBO);
    }


}
